treeBoundBox.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) 2017-2019 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 "treeBoundBox.H"
30 
31 // * * * * * * * * * * * * * * Static Data Members * * * * * * * * * * * * * //
32 
34 ({
35  face({0, 4, 6, 2}), // 0: x-min, left
36  face({1, 3, 7, 5}), // 1: x-max, right
37  face({0, 1, 5, 4}), // 2: y-min, bottom
38  face({2, 6, 7, 3}), // 3: y-max, top
39  face({0, 2, 3, 1}), // 4: z-min, back
40  face({4, 5, 7, 6}) // 5: z-max, front
41 });
42 
44 ({
45  {0, 1}, // 0
46  {1, 3},
47  {2, 3}, // 2
48  {0, 2},
49  {4, 5}, // 4
50  {5, 7},
51  {6, 7}, // 6
52  {4, 6},
53  {0, 4}, // 8
54  {1, 5},
55  {3, 7}, // 10
56  {2, 6}
57 });
58 
59 
60 // * * * * * * * * * * * * * * * * Constructors * * * * * * * * * * * * * * //
61 
63 :
64  boundBox(points, false)
65 {
66  if (points.empty())
67  {
69  << "No bounding box for zero-sized pointField" << nl;
70  }
71 }
72 
73 
75 (
76  const UList<point>& points,
77  const labelUList& indices
78 )
79 :
80  boundBox(points, indices, false)
81 {
82  if (points.empty() || indices.empty())
83  {
85  << "No bounding box for zero-sized pointField" << nl;
86  }
87 }
88 
89 
90 // * * * * * * * * * * * * * * * Member Functions * * * * * * * * * * * * * //
91 
93 {
94  auto tpts = tmp<pointField>::New(8);
95  auto& pts = tpts.ref();
96 
97  forAll(pts, octant)
98  {
99  pts[octant] = corner(octant);
100  }
101 
102  return tpts;
103 }
104 
105 
107 {
108  return subBbox(centre(), octant);
109 }
110 
111 
113 (
114  const point& mid,
115  const direction octant
116 ) const
117 {
118  if (octant > 7)
119  {
121  << "octant should be [0..7]"
122  << abort(FatalError);
123  }
124 
125  // start with a copy of this bounding box and adjust limits accordingly
126  treeBoundBox subBb(*this);
127  point& bbMin = subBb.min();
128  point& bbMax = subBb.max();
129 
130  if (octant & treeBoundBox::RIGHTHALF)
131  {
132  bbMin.x() = mid.x(); // mid -> max
133  }
134  else
135  {
136  bbMax.x() = mid.x(); // min -> mid
137  }
138 
139  if (octant & treeBoundBox::TOPHALF)
140  {
141  bbMin.y() = mid.y(); // mid -> max
142  }
143  else
144  {
145  bbMax.y() = mid.y(); // min -> mid
146  }
147 
148  if (octant & treeBoundBox::FRONTHALF)
149  {
150  bbMin.z() = mid.z(); // mid -> max
151  }
152  else
153  {
154  bbMax.z() = mid.z(); // min -> mid
155  }
156 
157  return subBb;
158 }
159 
160 
162 (
163  const point& overallStart,
164  const vector& overallVec,
165  const point& start,
166  const point& end,
167  point& pt,
168  direction& ptOnFaces
169 ) const
170 {
171  // Sutherlands algorithm:
172  // loop
173  // - start = intersection of line with one of the planes bounding
174  // the bounding box
175  // - stop if start inside bb (return true)
176  // - stop if start and end in same 'half' (e.g. both above bb)
177  // (return false)
178  //
179  // Uses posBits to efficiently determine 'half' in which start and end
180  // point are.
181  //
182  // Note:
183  // - sets coordinate to exact position: e.g. pt.x() = min().x()
184  // since plane intersect routine might have truncation error.
185  // This makes sure that posBits tests 'inside'
186 
187  const direction endBits = posBits(end);
188  pt = start;
189 
190  // Allow maximum of 3 clips.
191  for (label i = 0; i < 4; ++i)
192  {
193  direction ptBits = posBits(pt);
194 
195  if (ptBits == 0)
196  {
197  // pt inside bb
198  ptOnFaces = faceBits(pt);
199  return true;
200  }
201 
202  if ((ptBits & endBits) != 0)
203  {
204  // pt and end in same block outside of bb
205  ptOnFaces = faceBits(pt);
206  return false;
207  }
208 
209  if (ptBits & LEFTBIT)
210  {
211  // Intersect with plane V=min, n=-1,0,0
212  if (Foam::mag(overallVec.x()) > VSMALL)
213  {
214  scalar s = (min().x() - overallStart.x())/overallVec.x();
215  pt.x() = min().x();
216  pt.y() = overallStart.y() + overallVec.y()*s;
217  pt.z() = overallStart.z() + overallVec.z()*s;
218  }
219  else
220  {
221  // Vector not in x-direction. But still intersecting bb planes.
222  // So must be close - just snap to bb.
223  pt.x() = min().x();
224  }
225  }
226  else if (ptBits & RIGHTBIT)
227  {
228  // Intersect with plane V=max, n=1,0,0
229  if (Foam::mag(overallVec.x()) > VSMALL)
230  {
231  scalar s = (max().x() - overallStart.x())/overallVec.x();
232  pt.x() = max().x();
233  pt.y() = overallStart.y() + overallVec.y()*s;
234  pt.z() = overallStart.z() + overallVec.z()*s;
235  }
236  else
237  {
238  pt.x() = max().x();
239  }
240  }
241  else if (ptBits & BOTTOMBIT)
242  {
243  // Intersect with plane V=min, n=0,-1,0
244  if (Foam::mag(overallVec.y()) > VSMALL)
245  {
246  scalar s = (min().y() - overallStart.y())/overallVec.y();
247  pt.x() = overallStart.x() + overallVec.x()*s;
248  pt.y() = min().y();
249  pt.z() = overallStart.z() + overallVec.z()*s;
250  }
251  else
252  {
253  pt.x() = min().y();
254  }
255  }
256  else if (ptBits & TOPBIT)
257  {
258  // Intersect with plane V=max, n=0,1,0
259  if (Foam::mag(overallVec.y()) > VSMALL)
260  {
261  scalar s = (max().y() - overallStart.y())/overallVec.y();
262  pt.x() = overallStart.x() + overallVec.x()*s;
263  pt.y() = max().y();
264  pt.z() = overallStart.z() + overallVec.z()*s;
265  }
266  else
267  {
268  pt.y() = max().y();
269  }
270  }
271  else if (ptBits & BACKBIT)
272  {
273  // Intersect with plane V=min, n=0,0,-1
274  if (Foam::mag(overallVec.z()) > VSMALL)
275  {
276  scalar s = (min().z() - overallStart.z())/overallVec.z();
277  pt.x() = overallStart.x() + overallVec.x()*s;
278  pt.y() = overallStart.y() + overallVec.y()*s;
279  pt.z() = min().z();
280  }
281  else
282  {
283  pt.z() = min().z();
284  }
285  }
286  else if (ptBits & FRONTBIT)
287  {
288  // Intersect with plane V=max, n=0,0,1
289  if (Foam::mag(overallVec.z()) > VSMALL)
290  {
291  scalar s = (max().z() - overallStart.z())/overallVec.z();
292  pt.x() = overallStart.x() + overallVec.x()*s;
293  pt.y() = overallStart.y() + overallVec.y()*s;
294  pt.z() = max().z();
295  }
296  else
297  {
298  pt.z() = max().z();
299  }
300  }
301  }
302 
303  // Can end up here if the end point is on the edge of the boundBox
304  return true;
305 }
306 
307 
309 (
310  const point& start,
311  const point& end,
312  point& pt
313 ) const
314 {
315  direction ptBits;
316  return intersects(start, end-start, start, end, pt, ptBits);
317 }
318 
319 
320 bool Foam::treeBoundBox::contains(const vector& dir, const point& pt) const
321 {
322  // Compare all components against min and max of bb
323 
324  for (direction cmpt=0; cmpt<3; ++cmpt)
325  {
326  if (pt[cmpt] < min()[cmpt])
327  {
328  return false;
329  }
330  else if (pt[cmpt] == min()[cmpt])
331  {
332  // On edge. Outside if direction points outwards.
333  if (dir[cmpt] < 0)
334  {
335  return false;
336  }
337  }
338 
339  if (pt[cmpt] > max()[cmpt])
340  {
341  return false;
342  }
343  else if (pt[cmpt] == max()[cmpt])
344  {
345  // On edge. Outside if direction points outwards.
346  if (dir[cmpt] > 0)
347  {
348  return false;
349  }
350  }
351  }
352 
353  // All components inside bb
354  return true;
355 }
356 
357 
359 {
360  direction faceBits = 0;
361  if (pt.x() == min().x())
362  {
363  faceBits |= LEFTBIT;
364  }
365  else if (pt.x() == max().x())
366  {
367  faceBits |= RIGHTBIT;
368  }
369 
370  if (pt.y() == min().y())
371  {
372  faceBits |= BOTTOMBIT;
373  }
374  else if (pt.y() == max().y())
375  {
376  faceBits |= TOPBIT;
377  }
378 
379  if (pt.z() == min().z())
380  {
381  faceBits |= BACKBIT;
382  }
383  else if (pt.z() == max().z())
384  {
385  faceBits |= FRONTBIT;
386  }
387  return faceBits;
388 }
389 
390 
392 {
393  direction posBits = 0;
394 
395  if (pt.x() < min().x())
396  {
397  posBits |= LEFTBIT;
398  }
399  else if (pt.x() > max().x())
400  {
401  posBits |= RIGHTBIT;
402  }
403 
404  if (pt.y() < min().y())
405  {
406  posBits |= BOTTOMBIT;
407  }
408  else if (pt.y() > max().y())
409  {
410  posBits |= TOPBIT;
411  }
412 
413  if (pt.z() < min().z())
414  {
415  posBits |= BACKBIT;
416  }
417  else if (pt.z() > max().z())
418  {
419  posBits |= FRONTBIT;
420  }
421  return posBits;
422 }
423 
424 
426 (
427  const point& pt,
428  point& nearest,
429  point& furthest
430 ) const
431 {
432  scalar nearX, nearY, nearZ;
433  scalar farX, farY, farZ;
434 
435  if (Foam::mag(min().x() - pt.x()) < Foam::mag(max().x() - pt.x()))
436  {
437  nearX = min().x();
438  farX = max().x();
439  }
440  else
441  {
442  nearX = max().x();
443  farX = min().x();
444  }
445 
446  if (Foam::mag(min().y() - pt.y()) < Foam::mag(max().y() - pt.y()))
447  {
448  nearY = min().y();
449  farY = max().y();
450  }
451  else
452  {
453  nearY = max().y();
454  farY = min().y();
455  }
456 
457  if (Foam::mag(min().z() - pt.z()) < Foam::mag(max().z() - pt.z()))
458  {
459  nearZ = min().z();
460  farZ = max().z();
461  }
462  else
463  {
464  nearZ = max().z();
465  farZ = min().z();
466  }
467 
468  nearest = point(nearX, nearY, nearZ);
469  furthest = point(farX, farY, farZ);
470 }
471 
472 
473 Foam::scalar Foam::treeBoundBox::maxDist(const point& pt) const
474 {
475  point near, far;
476  calcExtremities(pt, near, far);
477 
478  return Foam::mag(far - pt);
479 }
480 
481 
483 (
484  const point& pt,
485  const treeBoundBox& other
486 ) const
487 {
488  //
489  // Distance point <-> nearest and furthest away vertex of this
490  //
491 
492  point nearThis, farThis;
493 
494  // get nearest and furthest away vertex
495  calcExtremities(pt, nearThis, farThis);
496 
497  const scalar minDistThis =
498  sqr(nearThis.x() - pt.x())
499  + sqr(nearThis.y() - pt.y())
500  + sqr(nearThis.z() - pt.z());
501  const scalar maxDistThis =
502  sqr(farThis.x() - pt.x())
503  + sqr(farThis.y() - pt.y())
504  + sqr(farThis.z() - pt.z());
505 
506  //
507  // Distance point <-> other
508  //
509 
510  point nearOther, farOther;
511 
512  // get nearest and furthest away vertex
513  other.calcExtremities(pt, nearOther, farOther);
514 
515  const scalar minDistOther =
516  sqr(nearOther.x() - pt.x())
517  + sqr(nearOther.y() - pt.y())
518  + sqr(nearOther.z() - pt.z());
519  const scalar maxDistOther =
520  sqr(farOther.x() - pt.x())
521  + sqr(farOther.y() - pt.y())
522  + sqr(farOther.z() - pt.z());
523 
524  //
525  // Categorize
526  //
527  if (maxDistThis < minDistOther)
528  {
529  // All vertices of this are nearer to point than any vertex of other
530  return -1;
531  }
532  else if (minDistThis > maxDistOther)
533  {
534  // All vertices of this are further from point than any vertex of other
535  return 1;
536  }
537  else
538  {
539  // Mixed bag
540  return 0;
541  }
542 }
543 
544 
545 // * * * * * * * * * * * * * * * Ostream Operator * * * * * * * * * * * * * //
546 
548 {
549  return os << static_cast<const boundBox&>(bb);
550 }
551 
552 
554 {
555  return is >> static_cast<boundBox&>(bb);
556 }
557 
558 
559 // ************************************************************************* //
Foam::treeBoundBox::TOPHALF
Definition: treeBoundBox.H:101
Foam::Vector::x
const Cmpt & x() const
Access to the vector x component.
Definition: VectorI.H:78
s
gmvFile<< "tracers "<< particles.size()<< nl;for(const passiveParticle &p :particles){ gmvFile<< p.position().x()<< " ";}gmvFile<< nl;for(const passiveParticle &p :particles){ gmvFile<< p.position().y()<< " ";}gmvFile<< nl;for(const passiveParticle &p :particles){ gmvFile<< p.position().z()<< " ";}gmvFile<< nl;forAll(lagrangianScalarNames, i){ word name=lagrangianScalarNames[i];IOField< scalar > s(IOobject(name, runTime.timeName(), cloud::prefix, mesh, IOobject::MUST_READ, IOobject::NO_WRITE))
Definition: gmvOutputSpray.H:25
Foam::treeBoundBox::points
tmp< pointField > points() const
Vertex coordinates. In octant coding.
Definition: treeBoundBox.C:92
Foam::tmp
A class for managing temporary objects.
Definition: PtrList.H:59
Foam::treeBoundBox
Standard boundBox with extra functionality for use in octree.
Definition: treeBoundBox.H:87
Foam::treeBoundBox::calcExtremities
void calcExtremities(const point &pt, point &nearest, point &furthest) const
Calculate nearest and furthest (to point) vertex coords of.
Definition: treeBoundBox.C:426
Foam::operator>>
Istream & operator>>(Istream &, directionInfo &)
Definition: directionInfo.C:228
Foam::treeBoundBox::edges
static const edgeList edges
Edge to point addressing.
Definition: treeBoundBox.H:153
Foam::boundBox::max
const point & max() const
Maximum describing the bounding box.
Definition: boundBoxI.H:97
Foam::treeBoundBox::RIGHTHALF
Definition: treeBoundBox.H:100
Foam::treeBoundBox::treeBoundBox
treeBoundBox()
Construct without any points - an inverted bounding box.
Definition: treeBoundBoxI.H:34
Foam::treeBoundBox::faceBits
direction faceBits(const point &pt) const
Code position of point on bounding box faces.
Definition: treeBoundBox.C:358
Foam::Vector::z
const Cmpt & z() const
Access to the vector z component.
Definition: VectorI.H:90
Foam::min
label min(const labelHashSet &set, label minValue=labelMax)
Find the min value in labelHashSet, optionally limited by second argument.
Definition: hashSets.C:33
Foam::boundBox::min
const point & min() const
Minimum describing the bounding box.
Definition: boundBoxI.H:91
Foam::treeBoundBox::subBbox
treeBoundBox subBbox(const direction octant) const
Sub-box of given octant. Midpoint calculated.
Definition: treeBoundBox.C:106
forAll
#define forAll(list, i)
Loop across all elements in list.
Definition: stdFoam.H:290
Foam::treeBoundBox::posBits
direction posBits(const point &pt) const
Position of point relative to bounding box.
Definition: treeBoundBox.C:391
Foam::label
intWM_LABEL_SIZE_t label
A label is an int32_t or int64_t as specified by the pre-processor macro WM_LABEL_SIZE.
Definition: label.H:62
Foam::Istream
An Istream is an abstract base class for all input systems (streams, files, token lists etc)....
Definition: Istream.H:61
treeBoundBox.H
Foam::treeBoundBox::intersects
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,.
Definition: treeBoundBox.C:162
Foam::treeBoundBox::faces
static const faceList faces
Face to point addressing.
Definition: treeBoundBox.H:150
Foam::max
label max(const labelHashSet &set, label maxValue=labelMin)
Find the max value in labelHashSet, optionally limited by second argument.
Definition: hashSets.C:47
Foam::UList::empty
bool empty() const noexcept
True if the UList is empty (ie, size() is zero)
Definition: UListI.H:374
Foam::FatalError
error FatalError
stdFoam::end
constexpr auto end(C &c) -> decltype(c.end())
Return iterator to the end of the container c.
Definition: stdFoam.H:115
Foam::abort
errorManip< error > abort(error &err)
Definition: errorManip.H:137
Foam::Vector::y
const Cmpt & y() const
Access to the vector y component.
Definition: VectorI.H:84
FatalErrorInFunction
#define FatalErrorInFunction
Report an error message using Foam::FatalError.
Definition: error.H:355
Foam::sqr
dimensionedSymmTensor sqr(const dimensionedVector &dv)
Definition: dimensionedSymmTensor.C:51
Foam::treeBoundBox::contains
bool contains(const vector &dir, const point &) const
Contains point (inside or on edge) and moving in direction.
Definition: treeBoundBox.C:320
Foam::nl
constexpr char nl
Definition: Ostream.H:372
Foam::treeBoundBox::maxDist
scalar maxDist(const point &pt) const
Returns distance point to furthest away corner.
Definition: treeBoundBox.C:473
Foam::treeBoundBox::FRONTHALF
Definition: treeBoundBox.H:102
Foam::Vector< scalar >
Foam::List
A 1D array of objects of type <T>, where the size of the vector is known and used for subscript bound...
Definition: HashTable.H:102
Foam::mag
dimensioned< typename typeOfMag< Type >::type > mag(const dimensioned< Type > &dt)
Foam::start
label ListType::const_reference const label start
Definition: ListOps.H:408
Foam::UList
A 1D vector of objects of type <T>, where the size of the vector is known and can be used for subscri...
Definition: HashTable.H:103
points
const pointField & points
Definition: gmvOutputHeader.H:1
Foam::tmp::New
static tmp< T > New(Args &&... args)
Construct tmp of T with forwarding arguments.
Foam::direction
uint8_t direction
Definition: direction.H:47
x
x
Definition: LISASMDCalcMethod2.H:52
Foam::boundBox
A bounding box defined in terms of min/max extrema points.
Definition: boundBox.H:63
Foam::treeBoundBox::distanceCmp
label distanceCmp(const point &pt, const treeBoundBox &other) const
Compare distance to point with other bounding box.
Definition: treeBoundBox.C:483
Foam::Ostream
An Ostream is an abstract base class for all output systems (streams, files, token lists,...
Definition: Ostream.H:56
Foam::point
vector point
Point is a vector.
Definition: point.H:43
WarningInFunction
#define WarningInFunction
Report a warning using Foam::Warning.
Definition: messageStream.H:294
Foam::operator<<
Ostream & operator<<(Ostream &, const boundaryPatch &)
Definition: boundaryPatch.C:102
y
scalar y
Definition: LISASMDCalcMethod1.H:14