boundBox.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) 2016-2023 OpenCFD Ltd.
10 -------------------------------------------------------------------------------
11 License
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 "boundBox.H"
30 #include "PstreamReduceOps.H"
31 #include "plane.H"
32 #include "hexCell.H"
33 #include "triangle.H"
34 #include "MinMax.H"
35 #include "Random.H"
36 
37 // * * * * * * * * * * * * * * Static Data Members * * * * * * * * * * * * * //
38 
40 (
41  point::uniform(-ROOTVGREAT),
42  point::uniform(ROOTVGREAT)
43 );
44 
46 (
47  point::uniform(ROOTVGREAT),
48  point::uniform(-ROOTVGREAT)
49 );
50 
52 ({
53  vector(-1, 0, 0), // 0: x-min, left
54  vector( 1, 0, 0), // 1: x-max, right
55  vector( 0, -1, 0), // 2: y-min, bottom
56  vector( 0, 1, 0), // 3: y-max, top
57  vector( 0, 0, -1), // 4: z-min, back
58  vector( 0, 0, 1) // 5: z-max, front
59 });
60 
61 
62 // * * * * * * * * * * * * * Static Member Functions * * * * * * * * * * * * //
63 
65 {
66  return hexCell::modelFaces();
67 }
68 
69 
70 // * * * * * * * * * * * * * * * * Constructors * * * * * * * * * * * * * * //
71 
72 Foam::boundBox::boundBox(const boundBox& bb, const bool doReduce)
73 :
74  boundBox(bb)
75 {
76  if (doReduce)
77  {
78  reduce();
79  }
80 }
81 
82 
83 Foam::boundBox::boundBox(const UList<point>& points, bool doReduce)
84 :
85  boundBox()
86 {
87  add(points);
88 
89  if (doReduce)
90  {
91  reduce();
92  }
93 }
94 
95 
96 Foam::boundBox::boundBox(const tmp<pointField>& tpoints, bool doReduce)
97 :
98  boundBox()
99 {
100  add(tpoints);
101 
102  if (doReduce)
103  {
104  reduce();
105  }
106 }
107 
108 
110 (
111  const UList<point>& points,
112  const labelUList& indices,
113  bool doReduce
114 )
115 :
116  boundBox()
117 {
118  add(points, indices);
119 
120  if (doReduce)
121  {
123  }
124 }
125 
126 
127 // * * * * * * * * * * * * * * Member Functions * * * * * * * * * * * * * * //
128 
130 {
132  auto& pts = tpts.ref();
133 
134  pts[0] = hexCorner<0>();
135  pts[1] = hexCorner<1>();
136  pts[2] = hexCorner<2>();
137  pts[3] = hexCorner<3>();
138  pts[4] = hexCorner<4>();
139  pts[5] = hexCorner<5>();
140  pts[6] = hexCorner<6>();
141  pts[7] = hexCorner<7>();
142 
143  return tpts;
144 }
145 
146 
148 {
149  auto tpts = tmp<pointField>::New(boundBox::nFaces());
150  auto& pts = tpts.ref();
151 
152  for (direction facei = 0; facei < boundBox::nFaces(); ++facei)
153  {
154  pts[facei] = faceCentre(facei);
155  }
156 
157  return tpts;
158 }
159 
160 
162 {
163  point pt = boundBox::centre();
164 
165  switch (facei)
166  {
167  case 0: pt.x() = min().x(); break; // 0: x-min, left
168  case 1: pt.x() = max().x(); break; // 1: x-max, right
169  case 2: pt.y() = min().y(); break; // 2: y-min, bottom
170  case 3: pt.y() = max().y(); break; // 3: y-max, top
171  case 4: pt.z() = min().z(); break; // 4: z-min, back
172  case 5: pt.z() = max().z(); break; // 5: z-max, front
173  default:
174  {
176  << "Face:" << int(facei) << " should be [0..5]"
177  << abort(FatalError);
178  }
179  }
180 
181  return pt;
182 }
183 
184 
186 {
187  Foam::reduce(min_, minOp<point>());
188  Foam::reduce(max_, maxOp<point>());
189 }
190 
191 
193 {
194  boundBox work(bb);
195  work.reduce();
196  return work;
197 }
198 
199 
200 bool Foam::boundBox::intersects(const plane& pln) const
201 {
202  // Require a full 3D box
203  if (nDim() != 3)
204  {
205  return false;
206  }
207 
208  // Check as below(1) or above(2) - stop when it cuts both
209  int side = 0;
210 
211  #undef doLocalCode
212  #define doLocalCode(Idx) \
213  { \
214  side |= (pln.whichSide(hexCorner<Idx>()) == plane::BACK ? 1 : 2); \
215  if (side == 3) return true; /* Both below and above: done */ \
216  }
217 
218  // Each box corner
219  doLocalCode(0);
220  doLocalCode(1);
221  doLocalCode(2);
222  doLocalCode(3);
223  doLocalCode(4);
224  doLocalCode(5);
225  doLocalCode(6);
226  doLocalCode(7);
228  #undef doLocalCode
229 
230  return false;
231 }
232 
233 
234 bool Foam::boundBox::intersects(const triPointRef& tri) const
235 {
236  // Require a full 3D box
237  if (nDim() != 3)
238  {
239  return false;
240  }
241 
242  // Simplest check - if any points are inside
243  if (contains(tri.a()) || contains(tri.b()) || contains(tri.c()))
244  {
245  return true;
246  }
247 
248 
249  // Extent of box points projected onto axis
250  const auto project_box = []
251  (
252  const boundBox& bb,
253  const vector& axis,
254  scalarMinMax& extent
255  ) -> void
256  {
257  extent.reset(axis & bb.hexCorner<0>());
258  extent.add(axis & bb.hexCorner<1>());
259  extent.add(axis & bb.hexCorner<2>());
260  extent.add(axis & bb.hexCorner<3>());
261  extent.add(axis & bb.hexCorner<4>());
262  extent.add(axis & bb.hexCorner<5>());
263  extent.add(axis & bb.hexCorner<6>());
264  extent.add(axis & bb.hexCorner<7>());
265  };
266 
267 
268  // Use separating axis theorem to determine if triangle and
269  // (axis-aligned) bounding box intersect.
270 
271  scalarMinMax tri_extent(0);
272  scalarMinMax box_extent(0);
273  const boundBox& bb = *this;
274 
275  // 1.
276  // Test separating axis defined by the box normals
277  // (project triangle points)
278  // - do first (largely corresponds to normal bound box rejection test)
279  //
280  // No intersection if extent of projected triangle points are outside
281  // of the box range
282 
283  {
284  // vector::X
285  tri_extent.reset(tri.a().x());
286  tri_extent.add(tri.b().x());
287  tri_extent.add(tri.c().x());
288 
289  box_extent.reset(bb.min().x(), bb.max().x());
290 
291  if (!tri_extent.overlaps(box_extent))
292  {
293  return false;
294  }
295 
296  // vector::Y
297  tri_extent.reset(tri.a().y());
298  tri_extent.add(tri.b().y());
299  tri_extent.add(tri.c().y());
300 
301  box_extent.reset(bb.min().y(), bb.max().y());
302 
303  if (!tri_extent.overlaps(box_extent))
304  {
305  return false;
306  }
307 
308  // vector::Z
309  tri_extent.reset(tri.a().z());
310  tri_extent.add(tri.b().z());
311  tri_extent.add(tri.c().z());
312 
313  box_extent.reset(bb.min().z(), bb.max().z());
314 
315  if (!tri_extent.overlaps(box_extent))
316  {
317  return false;
318  }
319  }
320 
321 
322  // 2.
323  // Test separating axis defined by the triangle normal
324  // (project box points)
325  // - can use area or unit normal since any scaling is applied to both
326  // sides of the comparison.
327  // - by definition all triangle points lie in the plane defined by
328  // the normal. It doesn't matter which of the points we use to define
329  // the triangle offset (extent) when projected onto the triangle normal
330 
331  vector axis = tri.areaNormal();
332 
333  tri_extent.reset(axis & tri.a());
334  project_box(bb, axis, box_extent);
335 
336  if (!tri_extent.overlaps(box_extent))
337  {
338  return false;
339  }
340 
341 
342  // 3.
343  // Test separating axes defined by the triangle edges, which are the
344  // cross product of the edge vectors and the box face normals
345 
346  for (const vector& edgeVec : { tri.vecA(), tri.vecB(), tri.vecC() })
347  {
348  for (direction faceDir = 0; faceDir < vector::nComponents; ++faceDir)
349  {
350  axis = Zero;
351  axis[faceDir] = 1;
352 
353  axis = (edgeVec ^ axis);
354 
355  // project tri
356  tri_extent.reset(axis & tri.a());
357  tri_extent.add(axis & tri.b());
358  tri_extent.add(axis & tri.c());
359 
360  project_box(bb, axis, box_extent);
361 
362  if (!tri_extent.overlaps(box_extent))
363  {
364  return false;
365  }
366  }
367  }
368 
369  return true;
370 }
371 
372 
373 bool Foam::boundBox::contains(const UList<point>& points) const
374 {
375  if (points.empty())
376  {
377  return true;
378  }
379 
380  for (const point& p : points)
381  {
382  if (!contains(p))
383  {
384  return false;
385  }
386  }
387 
388  return true;
389 }
390 
391 
392 bool Foam::boundBox::containsAny(const UList<point>& points) const
393 {
394  if (points.empty())
395  {
396  return true;
397  }
398 
399  for (const point& p : points)
400  {
401  if (contains(p))
402  {
403  return true;
404  }
405  }
406 
407  return false;
408 }
409 
410 
412 {
413  // Clip the point to the range of the bounding box
414  return point
415  (
416  Foam::min(Foam::max(p.x(), min_.x()), max_.x()),
417  Foam::min(Foam::max(p.y(), min_.y()), max_.y()),
418  Foam::min(Foam::max(p.z(), min_.z()), max_.z())
419  );
420 }
421 
422 
423 void Foam::boundBox::inflate(Random& rndGen, const scalar factor)
424 {
425  vector newSpan(span());
426 
427  // Make 3D
428  const scalar minSpan = factor * Foam::mag(newSpan);
429 
430  for (direction dir = 0; dir < vector::nComponents; ++dir)
431  {
432  newSpan[dir] = Foam::max(newSpan[dir], minSpan);
433  }
435  min_ -= cmptMultiply(factor*rndGen.sample01<vector>(), newSpan);
436  max_ += cmptMultiply(factor*rndGen.sample01<vector>(), newSpan);
437 }
438 
439 
441 (
442  Random& rndGen,
443  const scalar factor,
444  const scalar delta
445 )
446 {
447  inflate(rndGen, factor);
448  grow(delta);
449 }
450 
451 
452 // * * * * * * * * * * * * * * * Member Operators * * * * * * * * * * * * * //
453 
454 void Foam::boundBox::operator&=(const boundBox& bb)
455 {
456  min_ = ::Foam::max(min_, bb.min_);
457  max_ = ::Foam::min(max_, bb.max_);
458 }
459 
460 
461 // * * * * * * * * * * * * * * * Ostream Operator * * * * * * * * * * * * * //
462 
463 Foam::Ostream& Foam::operator<<(Ostream& os, const boundBox& bb)
464 {
466  {
467  os.write
468  (
469  reinterpret_cast<const char*>(&bb.min_),
470  sizeof(boundBox)
471  );
472  }
473  else
474  {
475  os << bb.min_ << token::SPACE << bb.max_;
476  }
477 
479  return os;
480 }
481 
482 
483 Foam::Istream& Foam::operator>>(Istream& is, boundBox& bb)
484 {
485  if (is.format() == IOstreamOption::BINARY)
486  {
487  Detail::readContiguous<boundBox>
488  (
489  is,
490  reinterpret_cast<char*>(&bb.min_),
491  sizeof(boundBox)
492  );
493  }
494  else
495  {
496  is >> bb.min_ >> bb.max_;
497  }
498 
499  is.check(FUNCTION_NAME);
500  return is;
501 }
502 
503 
504 // ************************************************************************* //
boundBox()
Default construct: an inverted bounding box.
Definition: boundBoxI.H:101
scalar delta
A triangle primitive used to calculate face normals and swept volumes. Uses referred points...
Definition: triangle.H:217
uint8_t direction
Definition: direction.H:46
Inter-processor communication reduction functions.
MinMax< scalar > scalarMinMax
A scalar min/max range.
Definition: MinMax.H:97
dimensioned< typename typeOfMag< Type >::type > mag(const dimensioned< Type > &dt)
virtual Ostream & write(const char c) override
Write character.
Definition: OBJstream.C:69
error FatalError
Error stream (stdout output on all processes), with additional &#39;FOAM FATAL ERROR&#39; header text and sta...
bool contains(const point &pt) const
Contains point? (inside or on edge)
Definition: boundBoxI.H:455
#define FatalErrorInFunction
Report an error message using Foam::FatalError.
Definition: error.H:598
virtual bool check(const char *operation) const
Check IOstream status for given operation.
Definition: IOstream.C:45
static const Foam::faceList & hexFaces()
The boundBox faces as a hexCell, using hexCorner points. Same as hexCell::modelFaces() ...
Definition: boundBox.C:57
void inflate(const scalar factor)
Expand box by factor*mag(span) in all dimensions.
Definition: boundBoxI.H:381
label max(const labelHashSet &set, label maxValue=labelMin)
Find the max value in labelHashSet, optionally limited by second argument.
Definition: hashSets.C:40
An Istream is an abstract base class for all input systems (streams, files, token lists etc)...
Definition: Istream.H:57
bool empty() const noexcept
True if List is empty (ie, size() is zero)
Definition: UList.H:666
Random rndGen
Definition: createFields.H:23
const Point & a() const noexcept
The first vertex.
Definition: triangle.H:371
A bounding box defined in terms of min/max extrema points.
Definition: boundBox.H:63
static boundBox returnReduce(const boundBox &bb)
Perform a reduction on a copy and return the result.
Definition: boundBox.C:185
static const FixedList< vector, 6 > faceNormals
The unit normal per face.
Definition: boundBox.H:129
::Foam::direction nComponents(const expressions::valueTypeCode) noexcept
The number of components associated with given valueTypeCode.
Definition: exprTraits.C:40
static const boundBox greatBox
A large boundBox: min/max == -/+ ROOTVGREAT.
Definition: boundBox.H:119
static const Foam::faceList & modelFaces()
Return the model faces.
Definition: hexCell.C:64
Geometric class that creates a 3D plane and can return the intersection point between a line and the ...
Definition: plane.H:90
bool intersects(const plane &pln) const
Does plane intersect this bounding box.
Definition: boundBox.C:193
const Point & c() const noexcept
The third vertex.
Definition: triangle.H:381
Point vecB() const
Edge vector opposite point b(): from c() to a()
Definition: triangleI.H:226
static constexpr label nPoints() noexcept
Number of points for boundBox and HEX.
Definition: boundBox.H:151
UList< label > labelUList
A UList of labels.
Definition: UList.H:78
void operator &=(const boundBox &bb)
Restrict min/max to union with other box.
tmp< pointField > hexCorners() const
Corner points in an order corresponding to a &#39;hex&#39; cell.
Definition: boundBox.C:122
void add(const boundBox &bb)
Extend to include the second box.
Definition: boundBoxI.H:323
Type sample01()
Return a sample whose components lie in the range [0,1].
const pointField & points
point nearest(const point &p) const
Return the nearest point on the boundBox to the supplied point.
Definition: boundBox.C:404
const Point & b() const noexcept
The second vertex.
Definition: triangle.H:376
static vector areaNormal(const Point &p0, const Point &p1, const Point &p2)
The area normal for a triangle defined by three points (right-hand rule). Magnitude equal to area of ...
Definition: triangleI.H:140
Point vecA() const
Edge vector opposite point a(): from b() to c()
Definition: triangleI.H:220
Istream & operator>>(Istream &, directionInfo &)
Space [isspace].
Definition: token.H:131
static tmp< T > New(Args &&... args)
Construct tmp with forwarding arguments.
Definition: tmp.H:206
tmp< pointField > faceCentres() const
Face midpoints.
Definition: boundBox.C:140
Vector< scalar > vector
Definition: vector.H:57
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
Random number generator.
Definition: Random.H:55
void reduce()
Inplace parallel reduction of min/max values.
Definition: boundBox.C:178
dimensioned< Type > cmptMultiply(const dimensioned< Type > &, const dimensioned< Type > &)
An Ostream is an abstract base class for all output systems (streams, files, token lists...
Definition: Ostream.H:56
A Vector of values with scalar precision, where scalar is float/double depending on the compilation f...
static constexpr label nFaces() noexcept
Number of faces for boundBox and HEX.
Definition: boundBox.H:161
OBJstream os(runTime.globalPath()/outputName)
#define FUNCTION_NAME
bool containsAny(const UList< point > &points) const
Contains any of the points? (inside or on edge)
Definition: boundBox.C:385
Ostream & operator<<(Ostream &, const boundaryPatch &p)
Write boundaryPatch as dictionary entries (without surrounding braces)
Definition: boundaryPatch.C:77
point faceCentre(const direction facei) const
Face centre of given face index.
Definition: boundBox.C:154
#define doLocalCode(Idx)
Point vecC() const
Edge vector opposite point c(): from a() to b()
Definition: triangleI.H:232
static const boundBox invertedBox
A large inverted boundBox: min/max == +/- ROOTVGREAT.
Definition: boundBox.H:124
vector point
Point is a vector.
Definition: point.H:37
tmp< pointField > points() const
Corner points in an order corresponding to a &#39;hex&#39; cell.
Definition: boundBox.H:374
void reduce(const List< UPstream::commsStruct > &comms, T &value, const BinaryOp &bop, const int tag, const label comm)
Reduce inplace (cf. MPI Allreduce) using specified communication schedule.
volScalarField & p
A class for managing temporary objects.
Definition: HashPtrTable.H:50
point centre() const
The centre (midpoint) of the bounding box.
Definition: boundBoxI.H:186
streamFormat format() const noexcept
Get the current stream format.
const pointField & pts
static constexpr const zero Zero
Global zero (0)
Definition: zero.H:127