Loading...
Searching...
No Matches
searchableBox.C
Go to the documentation of this file.
1/*---------------------------------------------------------------------------*\
2 ========= |
3 \\ / F ield | OpenFOAM: The Open Source CFD Toolbox
4 \\ / O peration |
5 \\ / A nd | www.openfoam.com
6 \\/ M anipulation |
7-------------------------------------------------------------------------------
8 Copyright (C) 2011-2016 OpenFOAM Foundation
9 Copyright (C) 2018-2022 OpenCFD Ltd.
10-------------------------------------------------------------------------------
11License
12 This file is part of OpenFOAM.
13
14 OpenFOAM is free software: you can redistribute it and/or modify it
15 under the terms of the GNU General Public License as published by
16 the Free Software Foundation, either version 3 of the License, or
17 (at your option) any later version.
18
19 OpenFOAM is distributed in the hope that it will be useful, but WITHOUT
20 ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
21 FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
22 for more details.
23
24 You should have received a copy of the GNU General Public License
25 along with OpenFOAM. If not, see <http://www.gnu.org/licenses/>.
26
27\*---------------------------------------------------------------------------*/
28
29#include "searchableBox.H"
32
33// * * * * * * * * * * * * * * Static Data Members * * * * * * * * * * * * * //
34
35namespace Foam
36{
39 (
42 dict
43 );
45 (
48 dict,
49 box
50 );
51}
52
54// * * * * * * * * * * * * * * * Local Functions * * * * * * * * * * * * * * //
55
56namespace Foam
57{
58
59// Read min/max or min/span
60static void readBoxDim(const dictionary& dict, treeBoundBox& bb)
61{
63
64 dict.readEntry("min", bb.min(), keyType::LITERAL, readOpt);
65
66 if (dict.readIfPresent("span", bb.max(), keyType::LITERAL))
67 {
68 bb.max() += bb.min();
70 }
71
72 dict.readEntry("max", bb.max(), keyType::LITERAL, readOpt);
73}
74
75} // End namespace Foam
76
77
78// * * * * * * * * * * * * * Private Member Functions * * * * * * * * * * * //
79
80void Foam::searchableBox::projectOntoCoordPlane
81(
82 const direction dir,
83 const point& planePt,
84 pointIndexHit& info
85) const
86{
87 // Set point
88 info.point()[dir] = planePt[dir];
89
90 // Set face
91 if (planePt[dir] == min()[dir])
92 {
93 info.setIndex(dir*2);
94 }
95 else if (planePt[dir] == max()[dir])
96 {
97 info.setIndex(dir*2+1);
98 }
99 else
100 {
102 << "Point on plane " << planePt
103 << " is not on coordinate " << min()[dir]
104 << " nor " << max()[dir] << nl
105 << abort(FatalError);
106 }
107}
108
109
110// Returns miss or hit with face (0..5) and region(always 0)
111Foam::pointIndexHit Foam::searchableBox::findNearest
112(
113 const point& bbMid,
114 const point& sample,
115 const scalar nearestDistSqr
116) const
117{
118 // Point can be inside or outside. For every component direction can be
119 // left of min, right of max or inbetween.
120 // - outside points: project first one x plane (either min().x()
121 // or max().x()), then onto y plane and finally z. You should be left
122 // with intersection point
123 // - inside point: find nearest side (compare to mid point). Project onto
124 // that.
125
126 // The face is set to the last projected face.
127
128
129 // Outside point projected onto cube. Assume faces 0..5.
130 pointIndexHit info(true, sample, -1);
131 bool outside = false;
132
133 // (for internal points) per direction what nearest cube side is
134 point near;
135
136 for (direction dir = 0; dir < vector::nComponents; ++dir)
137 {
138 if (info.point()[dir] < min()[dir])
139 {
140 projectOntoCoordPlane(dir, min(), info);
141 outside = true;
142 }
143 else if (info.point()[dir] > max()[dir])
144 {
145 projectOntoCoordPlane(dir, max(), info);
146 outside = true;
147 }
148 else if (info.point()[dir] > bbMid[dir])
149 {
150 near[dir] = max()[dir];
151 }
152 else
153 {
154 near[dir] = min()[dir];
155 }
156 }
157
158
159 // For outside points the info will be correct now. Handle inside points
160 // using the three near distances. Project onto the nearest plane.
161 if (!outside)
162 {
163 const vector dist(cmptMag(info.point() - near));
164
165 direction projNorm(vector::Z);
166
167 if (dist.x() < dist.y())
168 {
169 if (dist.x() < dist.z())
170 {
171 projNorm = vector::X;
172 }
173 }
174 else
175 {
176 if (dist.y() < dist.z())
177 {
178 projNorm = vector::Y;
179 }
180 }
181
182 projectOntoCoordPlane(projNorm, near, info);
183 }
184
185
186 // Check if outside. Optimisation: could do some checks on distance already
187 // on components above
188 if (info.point().distSqr(sample) > nearestDistSqr)
189 {
190 info.setMiss();
191 info.setIndex(-1);
192 }
194 return info;
195}
196
197
198// * * * * * * * * * * * * * * * * Constructors * * * * * * * * * * * * * * //
199
200Foam::searchableBox::searchableBox
201(
202 const IOobject& io,
203 const treeBoundBox& bb
204)
205:
207 treeBoundBox(bb)
208{
209 if (!treeBoundBox::good())
210 {
212 << "Illegal bounding box specification : "
213 << static_cast<const treeBoundBox>(*this) << nl
215 }
216
217 bounds() = static_cast<treeBoundBox>(*this);
218}
219
220
221Foam::searchableBox::searchableBox
222(
223 const IOobject& io,
224 const dictionary& dict
225)
226:
227 searchableSurface(io),
228 treeBoundBox()
229{
230 readBoxDim(dict, *this);
231
232 if (!treeBoundBox::good())
233 {
235 << "Illegal bounding box specification : "
236 << static_cast<const treeBoundBox>(*this) << nl
237 << exit(FatalError);
238 }
240 bounds() = static_cast<treeBoundBox>(*this);
241}
242
243
244// * * * * * * * * * * * * * * * Member Functions * * * * * * * * * * * * * //
245
247{
248 if (regions_.empty())
249 {
250 regions_.resize(1);
251 regions_[0] = "region0";
252 }
253 return regions_;
254}
255
256
258{
259 auto tctrs = tmp<pointField>::New(6);
260 auto& ctrs = tctrs.ref();
261
263 const faceList& fcs = treeBoundBox::faces;
264
265 forAll(fcs, i)
266 {
267 ctrs[i] = fcs[i].centre(pts);
268 }
269
270 return tctrs;
271}
272
273
275(
276 pointField& centres,
277 scalarField& radiusSqr
278) const
279{
280 centres.setSize(size());
281 radiusSqr.setSize(size());
282 radiusSqr = Zero;
283
285 const faceList& fcs = treeBoundBox::faces;
286
287 forAll(fcs, i)
288 {
289 const face& f = fcs[i];
290
291 centres[i] = f.centre(pts);
292 for (const label pointi : f)
293 {
294 const point& pt = pts[pointi];
295
296 radiusSqr[i] = Foam::max(radiusSqr[i], centres[i].distSqr(pt));
297 }
299
300 // Add a bit to make sure all points are tested inside
301 radiusSqr += Foam::sqr(SMALL);
302}
303
306{
307 return treeBoundBox::points();
308}
309
310
311Foam::pointIndexHit Foam::searchableBox::findNearest
312(
313 const point& sample,
314 const scalar nearestDistSqr
315) const
316{
317 return findNearest(centre(), sample, nearestDistSqr);
318}
319
320
322(
323 const point& sample,
324 const scalar nearestDistSqr
325) const
326{
327 const point bbMid(centre());
328
329 // Outside point projected onto cube. Assume faces 0..5.
330 pointIndexHit info(true, sample, -1);
331 bool outside = false;
332
333 // (for internal points) per direction what nearest cube side is
334 point near;
335
336 for (direction dir = 0; dir < vector::nComponents; ++dir)
337 {
338 if (info.point()[dir] < min()[dir])
339 {
340 projectOntoCoordPlane(dir, min(), info);
341 outside = true;
342 }
343 else if (info.point()[dir] > max()[dir])
344 {
345 projectOntoCoordPlane(dir, max(), info);
346 outside = true;
347 }
348 else if (info.point()[dir] > bbMid[dir])
349 {
350 near[dir] = max()[dir];
351 }
352 else
353 {
354 near[dir] = min()[dir];
355 }
356 }
357
358
359 // For outside points the info will be correct now. Handle inside points
360 // using the three near distances. Project onto the nearest two planes.
361 if (!outside)
362 {
363 // Get the per-component distance to nearest wall
364 vector dist(cmptMag(info.point() - near));
365
366 SortableList<scalar> sortedDist(3);
367 sortedDist[0] = dist[0];
368 sortedDist[1] = dist[1];
369 sortedDist[2] = dist[2];
370 sortedDist.sort();
371
372 // Project onto nearest
373 projectOntoCoordPlane(sortedDist.indices()[0], near, info);
374 // Project onto second nearest
375 projectOntoCoordPlane(sortedDist.indices()[1], near, info);
376 }
377
378
379 // Check if outside. Optimisation: could do some checks on distance already
380 // on components above
381 if (info.point().distSqr(sample) > nearestDistSqr)
382 {
383 info.setMiss();
384 info.setIndex(-1);
385 }
386
387 return info;
388}
389
390
391Foam::pointIndexHit Foam::searchableBox::findNearest
392(
393 const linePointRef& ln,
394 treeBoundBox& tightest,
395 point& linePoint
396) const
397{
399 return pointIndexHit();
400}
401
402
404(
405 const point& start,
406 const point& end
407) const
408{
409 pointIndexHit info(false, start, -1);
410
411 bool foundInter;
412
413 if (posBits(start) == 0)
414 {
415 if (posBits(end) == 0)
416 {
417 // Both start and end inside.
418 foundInter = false;
419 }
420 else
421 {
422 // end is outside. Clip to bounding box.
423 foundInter = intersects(end, start, info.point());
424 }
425 }
426 else
427 {
428 // start is outside. Clip to bounding box.
429 foundInter = intersects(start, end, info.point());
430 }
431
432
433 // Classify point
434 if (foundInter)
435 {
436 info.setHit();
437
438 for (direction dir = 0; dir < vector::nComponents; ++dir)
439 {
440 if (info.point()[dir] == min()[dir])
441 {
442 info.setIndex(2*dir);
443 break;
444 }
445 else if (info.point()[dir] == max()[dir])
446 {
447 info.setIndex(2*dir+1);
448 break;
449 }
450 }
451
452 if (info.index() == -1)
453 {
455 << "point " << info.point()
456 << " on segment " << start << end
457 << " should be on face of " << *this
458 << " but it isn't." << abort(FatalError);
460 }
461
462 return info;
463}
464
465
467(
468 const point& start,
469 const point& end
470) const
471{
472 return findLine(start, end);
473}
474
475
476void Foam::searchableBox::findNearest
477(
478 const pointField& samples,
479 const scalarField& nearestDistSqr,
481) const
482{
483 info.setSize(samples.size());
484
485 const point bbMid(centre());
486
488 {
489 info[i] = findNearest(bbMid, samples[i], nearestDistSqr[i]);
490 }
491}
492
493
495(
496 const pointField& start,
497 const pointField& end,
498 List<pointIndexHit>& info
499) const
500{
501 info.setSize(start.size());
502
503 forAll(start, i)
504 {
505 info[i] = findLine(start[i], end[i]);
506 }
507}
508
509
511(
512 const pointField& start,
513 const pointField& end,
514 List<pointIndexHit>& info
515) const
516{
517 info.setSize(start.size());
518
519 forAll(start, i)
520 {
521 info[i] = findLineAny(start[i], end[i]);
522 }
523}
524
525
527(
528 const pointField& start,
529 const pointField& end,
530 List<List<pointIndexHit>>& info
531) const
532{
533 info.setSize(start.size());
534
535 // Work array
536 DynamicList<pointIndexHit> hits;
537
538 // Tolerances:
539 // To find all intersections we add a small vector to the last intersection
540 // This is chosen such that
541 // - it is significant (SMALL is smallest representative relative tolerance;
542 // we need something bigger since we're doing calculations)
543 // - if the start-end vector is zero we still progress
544 const vectorField dirVec(end-start);
545 const scalarField magSqrDirVec(Foam::magSqr(dirVec));
546 const vectorField smallVec
547 (
548 ROOTSMALL*dirVec + vector::uniform(ROOTVSMALL)
549 );
550
551 forAll(start, pointi)
552 {
553 // See if any intersection between pt and end
554 pointIndexHit inter = findLine(start[pointi], end[pointi]);
555
556 if (inter.hit())
557 {
558 hits.clear();
559 hits.append(inter);
560
561 point pt = inter.hitPoint() + smallVec[pointi];
562
563 while (((pt-start[pointi])&dirVec[pointi]) <= magSqrDirVec[pointi])
564 {
565 // See if any intersection between pt and end
566 pointIndexHit inter = findLine(pt, end[pointi]);
567
568 // Check for not hit or hit same face as before (can happen
569 // if vector along surface of face)
570 if
571 (
572 !inter.hit()
573 || (inter.index() == hits.last().index())
574 )
575 {
576 break;
577 }
578 hits.append(inter);
579
580 pt = inter.hitPoint() + smallVec[pointi];
581 }
582
583 info[pointi].transfer(hits);
584 }
585 else
587 info[pointi].clear();
588 }
589 }
590}
591
592
594(
595 const List<pointIndexHit>& info,
596 labelList& region
597) const
598{
599 region.setSize(info.size());
600 region = 0;
601}
602
603
605(
606 const List<pointIndexHit>& info,
607 vectorField& normal
608) const
609{
610 normal.setSize(info.size());
611 normal = Zero;
612
613 forAll(info, i)
614 {
615 if (info[i].hit())
616 {
617 normal[i] = treeBoundBox::faceNormals[info[i].index()];
618 }
619 else
621 // Set to what?
622 }
623 }
624}
625
626
628(
629 const pointField& points,
630 List<volumeType>& volType
631) const
632{
633 volType.resize_nocopy(points.size());
634
635 forAll(points, pointi)
636 {
637 volType[pointi] =
638 (
642 );
643 }
644}
645
646
647// ************************************************************************* //
Macros for easy insertion into run-time selection tables.
#define addNamedToRunTimeSelectionTable(baseType, thisType, argNames, lookupName)
Add to construction table with 'lookupName' as the key.
#define addToRunTimeSelectionTable(baseType, thisType, argNames)
Add to construction table with typeName as the key.
A 1D vector of objects of type <T> that resizes itself as necessary to accept the new objects.
Definition DynamicList.H:68
void clear() noexcept
Clear the addressed list, i.e. set the size to zero.
void append(const T &val)
Copy append an element to the end of this list.
Minimal example by using system/controlDict.functions:
readOption
Enumeration defining read preferences.
@ READ_IF_PRESENT
Reading is optional [identical to LAZY_READ].
@ MUST_READ
Reading required.
Defines the attributes of an object for which implicit objectRegistry management is supported,...
Definition IOobject.H:191
InfoProxy< IOobject > info() const noexcept
Return info proxy, for printing information to a stream.
Definition IOobject.H:1041
A 1D array of objects of type <T>, where the size of the vector is known and used for subscript bound...
Definition List.H:72
void resize_nocopy(const label len)
Adjust allocated size of list without necessarily.
Definition ListI.H:171
void setSize(label n)
Alias for resize().
Definition List.H:536
label index() const noexcept
Return the hit index.
bool hit() const noexcept
Is there a hit?
const point_type & hitPoint() const
Return hit point. Fatal if not hit.
A list that is sorted upon construction or when explicitly requested with the sort() method.
const labelList & indices() const noexcept
Return the list of sorted indices. Updated every sort.
void sort()
Forward (stable) sort the list (if changed after construction).
void size(const label n)
Older name for setAddressableSize.
Definition UList.H:118
T & last()
Access last element of the list, position [size()-1].
Definition UList.H:971
static constexpr direction nComponents
Number of components in this vector space.
static Form uniform(const Cmpt &s)
Return a VectorSpace with all elements = s.
const point & max() const noexcept
Maximum describing the bounding box.
Definition boundBoxI.H:168
const point & min() const noexcept
Minimum describing the bounding box.
Definition boundBoxI.H:162
bool good() const
Bounding box is non-inverted.
Definition boundBoxI.H:156
point centre() const
The centre (midpoint) of the bounding box.
Definition boundBoxI.H:186
static const FixedList< vector, 6 > faceNormals
The unit normal per face.
Definition boundBox.H:136
A list of keyword definitions, which are a keyword followed by a number of values (eg,...
Definition dictionary.H:133
A face is a list of labels corresponding to mesh vertices.
Definition face.H:71
@ LITERAL
String literal.
Definition keyType.H:82
Searching on bounding box.
virtual label size() const
Range of local indices that can be returned.
virtual void findLineAll(const pointField &start, const pointField &end, List< List< pointIndexHit > > &) const
Get all intersections in order from start to end.
virtual void boundingSpheres(pointField &centres, scalarField &radiusSqr) const
Get bounding spheres (centre and radius squared), one per element.
virtual void getVolumeType(const pointField &points, List< volumeType > &volType) const
Determine type (inside/outside) for points.
pointIndexHit findNearestOnEdge(const point &sample, const scalar nearestDistSqr) const
Calculate nearest point on edge.
virtual void getNormal(const List< pointIndexHit > &, vectorField &normal) const
From a set of points and indices get the normal.
pointIndexHit findLine(const point &start, const point &end) const
Find nearest intersection of line between start and end.
virtual void getRegion(const List< pointIndexHit > &, labelList &region) const
From a set of points and indices get the region.
virtual const wordList & regions() const
Names of regions.
virtual tmp< pointField > coordinates() const
Get representative set of element coordinates.
pointIndexHit findLineAny(const point &start, const point &end) const
Find any intersection of line between start and end.
virtual tmp< pointField > points() const
Get the points that define the surface.
Base class of (analytical or triangulated) surface. Encapsulates all the search routines....
virtual const boundBox & bounds() const
Return const reference to boundBox.
A class for managing temporary objects.
Definition tmp.H:75
static tmp< T > New(Args &&... args)
Construct tmp with forwarding arguments.
Definition tmp.H:215
Standard boundBox with extra functionality for use in octree.
static const faceList faces
Face to point addressing, using octant corner points.
tmp< pointField > points() const
Vertex coordinates. In octant coding.
bool intersects(const point &overallStart, const vector &overallVec, const point &start, const point &end, point &pt, direction &ptBits) const
Intersects segment; set point to intersection position and face,.
treeBoundBox()=default
Default construct: an inverted bounding box.
bool contains(const vector &dir, const point &) const
Contains point (inside or on edge) and moving in direction.
direction posBits(const point &pt) const
Position of point relative to bounding box.
@ OUTSIDE
A location outside the volume.
Definition volumeType.H:66
@ INSIDE
A location inside the volume.
Definition volumeType.H:65
#define defineTypeNameAndDebug(Type, DebugSwitch)
Define the typeName and debug information.
Definition className.H:142
#define NotImplemented
Issue a FatalErrorIn for a function not currently implemented.
Definition error.H:688
#define FatalErrorInFunction
Report an error message using Foam::FatalError.
Definition error.H:600
const auto & io
const pointField & points
const char * end
Definition SVGTools.H:223
Namespace for OpenFOAM.
List< word > wordList
List of word.
Definition fileName.H:60
label max(const labelHashSet &set, label maxValue=labelMin)
Find the max value in labelHashSet, optionally limited by second argument.
Definition hashSets.C:40
List< label > labelList
A List of labels.
Definition List.H:62
dimensionedSymmTensor sqr(const dimensionedVector &dv)
List< face > faceList
List of faces.
Definition faceListFwd.H:41
static void readBoxDim(const dictionary &dict, treeBoundBox &bb)
Field< scalar > scalarField
Specialisation of Field<T> for scalar.
line< point, const point & > linePointRef
A line using referred points.
Definition line.H:66
label min(const labelHashSet &set, label minValue=labelMax)
Find the min value in labelHashSet, optionally limited by second argument.
Definition hashSets.C:26
errorManip< error > abort(error &err)
Definition errorManip.H:139
Field< vector > vectorField
Specialisation of Field<T> for vector.
uint8_t direction
Definition direction.H:49
vector point
Point is a vector.
Definition point.H:37
static constexpr const zero Zero
Global zero (0).
Definition zero.H:127
error FatalError
Error stream (stdout output on all processes), with additional 'FOAM FATAL ERROR' header text and sta...
void cmptMag(FieldField< Field, Type > &cf, const FieldField< Field, Type > &f)
vectorField pointField
pointField is a vectorField.
Vector< scalar > vector
Definition vector.H:57
PointIndexHit< point > pointIndexHit
A PointIndexHit with a 3D point.
errorManipArg< error, int > exit(error &err, const int errNo=1)
Definition errorManip.H:125
bool ln(const fileName &src, const fileName &dst)
Create a softlink. dst should not exist. Returns true if successful.
Definition POSIX.C:1239
dimensioned< typename typeOfMag< Type >::type > magSqr(const dimensioned< Type > &dt)
constexpr char nl
The newline '\n' character (0x0a).
Definition Ostream.H:50
labelList f(nPoints)
dictionary dict
const pointField & pts
#define forAll(list, i)
Loop across all elements in list.
Definition stdFoam.H:299
scalarField samples(nIntervals, Zero)