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-2022 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 
33 // Point order using octant points
35 ({
36  face({0, 4, 6, 2}), // 0: x-min, left
37  face({1, 3, 7, 5}), // 1: x-max, right
38  face({0, 1, 5, 4}), // 2: y-min, bottom
39  face({2, 6, 7, 3}), // 3: y-max, top
40  face({0, 2, 3, 1}), // 4: z-min, back
41  face({4, 5, 7, 6}) // 5: z-max, front
42 });
43 
44 // Point order using octant points
46 ({
47  {0, 1}, // 0
48  {1, 3},
49  {2, 3}, // 2
50  {0, 2},
51  {4, 5}, // 4
52  {5, 7},
53  {6, 7}, // 6
54  {4, 6},
55  {0, 4}, // 8
56  {1, 5},
57  {3, 7}, // 10
58  {2, 6}
59 });
60 
61 
62 // * * * * * * * * * * * * * * * * Constructors * * * * * * * * * * * * * * //
63 
64 Foam::treeBoundBox::treeBoundBox(const UList<point>& points)
65 :
66  boundBox(points, false)
67 {
68  if (points.empty())
69  {
71  << "No bounding box for zero-sized pointField" << nl;
72  }
73 }
74 
75 
77 (
78  const UList<point>& points,
79  const labelUList& indices
80 )
81 :
82  boundBox(points, indices, false)
83 {
84  if (points.empty() || indices.empty())
85  {
87  << "No bounding box for zero-sized pointField" << nl;
88  }
89 }
90 
91 
92 // * * * * * * * * * * * * * * * Member Functions * * * * * * * * * * * * * //
93 
95 {
96  auto tpts = tmp<pointField>::New(8);
97  auto& pts = tpts.ref();
98 
99  forAll(pts, octant)
100  {
101  pts[octant] = corner(octant);
102  }
103 
104  return tpts;
105 }
106 
107 
109 (
110  const point& mid,
111  const direction octant
112 ) const
113 {
114  if (octant > 7)
115  {
117  << "octant:" << int(octant) << " should be [0..7]"
118  << abort(FatalError);
119  }
120 
121  // Start the box with a single point (the mid-point) and push out the
122  // min/max dimensions according to the octant.
123 
124  treeBoundBox bb(mid);
125 
126  if (octant & treeBoundBox::RIGHTHALF)
127  {
128  bb.max().x() = max().x();
129  }
130  else
131  {
132  bb.min().x() = min().x();
133  }
134 
135  if (octant & treeBoundBox::TOPHALF)
136  {
137  bb.max().y() = max().y();
138  }
139  else
140  {
141  bb.min().y() = min().y();
142  }
143 
144  if (octant & treeBoundBox::FRONTHALF)
145  {
146  bb.max().z() = max().z();
147  }
148  else
149  {
150  bb.min().z() = min().z();
151  }
152 
153  return bb;
154 }
155 
156 
158 (
159  const scalar mid,
160  const direction whichFace
161 ) const
162 {
163  // Start with a copy of this bounding box and adjust limits accordingly
164  // - corresponds to a clipping plane
165 
166  treeBoundBox bb(*this);
167 
168  switch (whichFace)
169  {
170  case LEFT : bb.max().x() = mid; break;
171  case RIGHT : bb.min().x() = mid; break;
172 
173  case BOTTOM : bb.max().y() = mid; break;
174  case TOP : bb.min().y() = mid; break;
175 
176  case BACK : bb.max().z() = mid; break;
177  case FRONT : bb.min().z() = mid; break;
178 
179  default:
180  {
182  << "face:" << int(whichFace) << " should be [0..5]"
183  << abort(FatalError);
184  }
185  }
186 
187  return bb;
188 }
189 
190 
192 (
193  const direction whichFace
194 ) const
195 {
196  direction cmpt =
197  (
198  (whichFace == faceId::LEFT || whichFace == faceId::RIGHT)
199  ? vector::X
200  : (whichFace == faceId::BOTTOM || whichFace == faceId::TOP)
201  ? vector::Y
202  : vector::Z
203  );
205  scalar mid = 0.5*(min()[cmpt] + max()[cmpt]);
206 
207  return subHalf(mid, whichFace);
208 }
209 
210 
212 {
213  return subBbox(centre(), octant);
214 }
215 
216 
218 (
219  const direction octant,
220  const boundBox& bb
221 ) const
222 {
223  // Slightly accelerated version of
224  // subBbox(octant).overlaps(bb)
225 
226  point subMin = centre();
227  point subMax = subMin;
228 
229  if (octant & RIGHTHALF)
230  {
231  subMax.x() = max().x();
232  }
233  else
234  {
235  subMin.x() = min().x();
236  }
237 
238  if (octant & TOPHALF)
239  {
240  subMax.y() = max().y();
241  }
242  else
243  {
244  subMin.y() = min().y();
245  }
246 
247  if (octant & FRONTHALF)
248  {
249  subMax.z() = max().z();
250  }
251  else
252  {
253  subMin.z() = min().z();
254  }
256  // NB: ordering of corners *is* irrelevant
257  return box_box_overlaps(subMin, subMax, bb.min(), bb.max());
258 }
259 
260 
262 (
263  const point& overallStart,
264  const vector& overallVec,
265  const point& start,
266  const point& end,
267  point& pt,
268  direction& ptOnFaces
269 ) const
270 {
271  // Sutherlands algorithm:
272  // loop
273  // - start = intersection of line with one of the planes bounding
274  // the bounding box
275  // - stop if start inside bb (return true)
276  // - stop if start and end in same 'half' (e.g. both above bb)
277  // (return false)
278  //
279  // Uses posBits to efficiently determine 'half' in which start and end
280  // point are.
281  //
282  // Note:
283  // - sets coordinate to exact position: e.g. pt.x() = min().x()
284  // since plane intersect routine might have truncation error.
285  // This makes sure that posBits tests 'inside'
286 
287  const direction endBits = posBits(end);
288  pt = start;
289 
290  // Allow maximum of 3 clips.
291  for (direction i = 0; i < 4; ++i)
292  {
293  direction ptBits = posBits(pt);
294 
295  if (ptBits == 0)
296  {
297  // pt inside bb
298  ptOnFaces = faceBits(pt);
299  return true;
300  }
301 
302  if ((ptBits & endBits) != 0)
303  {
304  // pt and end in same block outside of bb
305  ptOnFaces = faceBits(pt);
306  return false;
307  }
308 
309  if (ptBits & LEFTBIT)
310  {
311  // Intersect with plane V=min, n=-1,0,0
312  if (Foam::mag(overallVec.x()) > VSMALL)
313  {
314  scalar s = (min().x() - overallStart.x())/overallVec.x();
315  pt.x() = min().x();
316  pt.y() = overallStart.y() + overallVec.y()*s;
317  pt.z() = overallStart.z() + overallVec.z()*s;
318  }
319  else
320  {
321  // Vector not in x-direction. But still intersecting bb planes.
322  // So must be close - just snap to bb.
323  pt.x() = min().x();
324  }
325  }
326  else if (ptBits & RIGHTBIT)
327  {
328  // Intersect with plane V=max, n=1,0,0
329  if (Foam::mag(overallVec.x()) > VSMALL)
330  {
331  scalar s = (max().x() - overallStart.x())/overallVec.x();
332  pt.x() = max().x();
333  pt.y() = overallStart.y() + overallVec.y()*s;
334  pt.z() = overallStart.z() + overallVec.z()*s;
335  }
336  else
337  {
338  pt.x() = max().x();
339  }
340  }
341  else if (ptBits & BOTTOMBIT)
342  {
343  // Intersect with plane V=min, n=0,-1,0
344  if (Foam::mag(overallVec.y()) > VSMALL)
345  {
346  scalar s = (min().y() - overallStart.y())/overallVec.y();
347  pt.x() = overallStart.x() + overallVec.x()*s;
348  pt.y() = min().y();
349  pt.z() = overallStart.z() + overallVec.z()*s;
350  }
351  else
352  {
353  pt.x() = min().y();
354  }
355  }
356  else if (ptBits & TOPBIT)
357  {
358  // Intersect with plane V=max, n=0,1,0
359  if (Foam::mag(overallVec.y()) > VSMALL)
360  {
361  scalar s = (max().y() - overallStart.y())/overallVec.y();
362  pt.x() = overallStart.x() + overallVec.x()*s;
363  pt.y() = max().y();
364  pt.z() = overallStart.z() + overallVec.z()*s;
365  }
366  else
367  {
368  pt.y() = max().y();
369  }
370  }
371  else if (ptBits & BACKBIT)
372  {
373  // Intersect with plane V=min, n=0,0,-1
374  if (Foam::mag(overallVec.z()) > VSMALL)
375  {
376  scalar s = (min().z() - overallStart.z())/overallVec.z();
377  pt.x() = overallStart.x() + overallVec.x()*s;
378  pt.y() = overallStart.y() + overallVec.y()*s;
379  pt.z() = min().z();
380  }
381  else
382  {
383  pt.z() = min().z();
384  }
385  }
386  else if (ptBits & FRONTBIT)
387  {
388  // Intersect with plane V=max, n=0,0,1
389  if (Foam::mag(overallVec.z()) > VSMALL)
390  {
391  scalar s = (max().z() - overallStart.z())/overallVec.z();
392  pt.x() = overallStart.x() + overallVec.x()*s;
393  pt.y() = overallStart.y() + overallVec.y()*s;
394  pt.z() = max().z();
395  }
396  else
397  {
398  pt.z() = max().z();
399  }
400  }
401  }
403  // Can end up here if the end point is on the edge of the boundBox
404  return true;
405 }
406 
407 
409 (
410  const point& start,
411  const point& end,
412  point& pt
413 ) const
414 {
415  direction ptBits;
416  return intersects(start, end-start, start, end, pt, ptBits);
417 }
418 
419 
420 bool Foam::treeBoundBox::contains(const vector& dir, const point& pt) const
421 {
422  // Compare all components against min and max of bb
423 
424  for (direction cmpt=0; cmpt < point::nComponents; ++cmpt)
425  {
426  if (pt[cmpt] < min()[cmpt])
427  {
428  return false;
429  }
430  else if (pt[cmpt] == min()[cmpt])
431  {
432  // On edge. Outside if direction points outwards.
433  if (dir[cmpt] < 0)
434  {
435  return false;
436  }
437  }
438 
439  if (pt[cmpt] > max()[cmpt])
440  {
441  return false;
442  }
443  else if (pt[cmpt] == max()[cmpt])
444  {
445  // On edge. Outside if direction points outwards.
446  if (dir[cmpt] > 0)
447  {
448  return false;
449  }
450  }
451  }
452 
453  // All components inside bb
454  return true;
455 }
456 
457 
459 {
460  direction octant = 0;
461 
462  if (pt.x() == min().x())
463  {
464  octant |= LEFTBIT;
465  }
466  else if (pt.x() == max().x())
467  {
468  octant |= RIGHTBIT;
469  }
470 
471  if (pt.y() == min().y())
472  {
473  octant |= BOTTOMBIT;
474  }
475  else if (pt.y() == max().y())
476  {
477  octant |= TOPBIT;
478  }
479 
480  if (pt.z() == min().z())
481  {
482  octant |= BACKBIT;
483  }
484  else if (pt.z() == max().z())
485  {
486  octant |= FRONTBIT;
487  }
488 
489  return octant;
490 }
491 
492 
494 {
495  direction octant = 0;
496 
497  if (pt.x() < min().x())
498  {
499  octant |= LEFTBIT;
500  }
501  else if (pt.x() > max().x())
502  {
503  octant |= RIGHTBIT;
504  }
505 
506  if (pt.y() < min().y())
507  {
508  octant |= BOTTOMBIT;
509  }
510  else if (pt.y() > max().y())
511  {
512  octant |= TOPBIT;
513  }
514 
515  if (pt.z() < min().z())
516  {
517  octant |= BACKBIT;
518  }
519  else if (pt.z() > max().z())
520  {
521  octant |= FRONTBIT;
522  }
523 
524  return octant;
525 }
526 
527 
529 (
530  const point& pt,
531  point& nearest,
532  point& furthest
533 ) const
534 {
535  for (direction cmpt=0; cmpt < point::nComponents; ++cmpt)
536  {
537  if
538  (
539  Foam::mag(min()[cmpt] - pt[cmpt])
540  < Foam::mag(max()[cmpt] - pt[cmpt])
541  )
542  {
543  nearest[cmpt] = min()[cmpt];
544  furthest[cmpt] = max()[cmpt];
545  }
546  else
547  {
548  nearest[cmpt] = max()[cmpt];
549  furthest[cmpt] = min()[cmpt];
550  }
551  }
552 }
553 
554 
555 Foam::scalar Foam::treeBoundBox::maxDist(const point& pt) const
556 {
557  point near, far;
558  calcExtremities(pt, near, far);
559 
560  return pt.dist(far);
561 }
562 
563 
565 (
566  const point& pt,
567  const treeBoundBox& other
568 ) const
569 {
570  //
571  // Distance point <-> nearest and furthest away vertex of this
572  //
573 
574  point nearThis, farThis;
575 
576  // get nearest and furthest away vertex
577  calcExtremities(pt, nearThis, farThis);
578 
579  const scalar minDistThis = pt.distSqr(nearThis);
580  const scalar maxDistThis = pt.distSqr(farThis);
581 
582  //
583  // Distance point <-> other
584  //
585 
586  point nearOther, farOther;
587 
588  // get nearest and furthest away vertex
589  other.calcExtremities(pt, nearOther, farOther);
590 
591  const scalar minDistOther = pt.distSqr(nearOther);
592  const scalar maxDistOther = pt.distSqr(farOther);
593 
594  //
595  // Categorize
596  //
597  if (maxDistThis < minDistOther)
598  {
599  // All vertices of this are nearer to point than any vertex of other
600  return -1;
601  }
602  else if (minDistThis > maxDistOther)
603  {
604  // All vertices of this are further from point than any vertex of other
605  return 1;
606  }
607  else
608  {
609  // Mixed bag
610  return 0;
611  }
612 }
613 
614 
615 // * * * * * * * * * * * * * * * Ostream Operator * * * * * * * * * * * * * //
618 {
619  return os << static_cast<const boundBox&>(bb);
620 }
621 
622 
623 Foam::Istream& Foam::operator>>(Istream& is, treeBoundBox& bb)
624 {
625  return is >> static_cast<boundBox&>(bb);
626 }
627 
628 
629 // ************************************************************************* //
direction faceBits(const point &pt) const
Code position of point on bounding box faces.
Definition: treeBoundBox.C:451
treeBoundBox subHalf(const direction whichFace) const
Sub-box half for given face.
Definition: treeBoundBox.C:185
uint8_t direction
Definition: direction.H:46
bool subOverlaps(const direction octant, const boundBox &bb) const
Does sub-octant overlap/touch boundingBox?
Definition: treeBoundBox.C:211
dimensioned< typename typeOfMag< Type >::type > mag(const dimensioned< Type > &dt)
error FatalError
Error stream (stdout output on all processes), with additional &#39;FOAM FATAL ERROR&#39; header text and sta...
#define FatalErrorInFunction
Report an error message using Foam::FatalError.
Definition: error.H:598
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
constexpr char nl
The newline &#39;\n&#39; character (0x0a)
Definition: Ostream.H:50
A bounding box defined in terms of min/max extrema points.
Definition: boundBox.H:63
::Foam::direction nComponents(const expressions::valueTypeCode) noexcept
The number of components associated with given valueTypeCode.
Definition: exprTraits.C:40
label distanceCmp(const point &pt, const treeBoundBox &other) const
Compare distance to point with other bounding box.
Definition: treeBoundBox.C:558
const point & min() const noexcept
Minimum describing the bounding box.
Definition: boundBoxI.H:162
static const faceList faces
Face to point addressing, using octant corner points.
Definition: treeBoundBox.H:174
1: positive x-direction
Definition: treeBoundBox.H:106
UList< label > labelUList
A UList of labels.
Definition: UList.H:78
#define forAll(list, i)
Loop across all elements in list.
Definition: stdFoam.H:421
direction posBits(const point &pt) const
Position of point relative to bounding box.
Definition: treeBoundBox.C:486
const point & max() const noexcept
Maximum describing the bounding box.
Definition: boundBoxI.H:168
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:255
const pointField & points
Istream & operator>>(Istream &, directionInfo &)
static const edgeList edges
Edge to point addressing, using octant corner points.
Definition: treeBoundBox.H:179
static tmp< T > New(Args &&... args)
Construct tmp with forwarding arguments.
Definition: tmp.H:206
treeBoundBox subBbox(const direction octant) const
Sub-box of given octant. Midpoint calculated.
Definition: treeBoundBox.C:204
treeBoundBox()=default
Default construct: an inverted bounding box.
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
void calcExtremities(const point &pt, point &nearest, point &furthest) const
Calculate nearest and furthest (to point) vertex coords of.
Definition: treeBoundBox.C:522
bool contains(const vector &dir, const point &) const
Contains point (inside or on edge) and moving in direction.
Definition: treeBoundBox.C:413
An Ostream is an abstract base class for all output systems (streams, files, token lists...
Definition: Ostream.H:56
scalar maxDist(const point &pt) const
Returns distance point to furthest away corner.
Definition: treeBoundBox.C:548
A Vector of values with scalar precision, where scalar is float/double depending on the compilation f...
constexpr auto end(C &c) -> decltype(c.end())
Return iterator to the end of the container c.
Definition: stdFoam.H:201
OBJstream os(runTime.globalPath()/outputName)
4: positive z-direction
Definition: treeBoundBox.H:108
Ostream & operator<<(Ostream &, const boundaryPatch &p)
Write boundaryPatch as dictionary entries (without surrounding braces)
Definition: boundaryPatch.C:77
vector point
Point is a vector.
Definition: point.H:37
#define WarningInFunction
Report a warning using Foam::Warning.
PtrList< volScalarField > & Y
tmp< pointField > points() const
Vertex coordinates. In octant coding.
Definition: treeBoundBox.C:87
Standard boundBox with extra functionality for use in octree.
Definition: treeBoundBox.H:90
A class for managing temporary objects.
Definition: HashPtrTable.H:50
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))
2: positive y-direction
Definition: treeBoundBox.H:107
const pointField & pts