1 /*---------------------------------------------------------------------------*\
3 \\ / F ield | OpenFOAM: The Open Source CFD Toolbox
5 \\ / A nd | Copyright (C) 2011 OpenFOAM Foundation
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
13 the Free Software Foundation, either version 3 of the License, or
14 (at your 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, see <http://www.gnu.org/licenses/>.
24 \*---------------------------------------------------------------------------*/
26 #include "treeBoundBox.H"
29 // * * * * * * * * * * * * * * Static Data Members * * * * * * * * * * * * * //
31 const Foam::scalar Foam::treeBoundBox::great(GREAT);
33 const Foam::treeBoundBox Foam::treeBoundBox::greatBox
35 vector(-GREAT, -GREAT, -GREAT),
36 vector(GREAT, GREAT, GREAT)
40 const Foam::treeBoundBox Foam::treeBoundBox::invertedBox
42 vector(GREAT, GREAT, GREAT),
43 vector(-GREAT, -GREAT, -GREAT)
47 //! \cond - skip documentation : local scope only
48 const Foam::label facesArray[6][4] =
51 {1, 3, 7, 5}, // right
52 {0, 1, 5, 4}, // bottom
60 const Foam::faceList Foam::treeBoundBox::faces
62 initListList<face, label, 6, 4>(facesArray)
66 //! \cond - skip documentation : local scope only
67 const Foam::label edgesArray[12][2] =
85 const Foam::edgeList Foam::treeBoundBox::edges
87 //initListList<edge, label, 12, 2>(edgesArray)
92 const Foam::FixedList<Foam::vector, 6> Foam::treeBoundBox::faceNormals
98 // * * * * * * * * * * * * * Private Member Functions * * * * * * * * * * * //
100 Foam::edgeList Foam::treeBoundBox::calcEdges(const label edgesArray[12][2])
105 edges[edgeI][0] = edgesArray[edgeI][0];
106 edges[edgeI][1] = edgesArray[edgeI][1];
112 Foam::FixedList<Foam::vector, 6> Foam::treeBoundBox::calcFaceNormals()
114 FixedList<vector, 6> normals;
115 normals[LEFT] = vector(-1, 0, 0);
116 normals[RIGHT] = vector( 1, 0, 0);
117 normals[BOTTOM] = vector( 0, -1, 0);
118 normals[TOP] = vector( 0, 1, 0);
119 normals[BACK] = vector( 0, 0, -1);
120 normals[FRONT] = vector( 0, 0, 1);
125 // * * * * * * * * * * * * * * * * Constructors * * * * * * * * * * * * * * //
127 Foam::treeBoundBox::treeBoundBox(const UList<point>& points)
129 boundBox(points, false)
135 "treeBoundBox::treeBoundBox(const UList<point>&)"
136 ) << "cannot find bounding box for zero-sized pointField, "
137 << "returning zero" << endl;
144 Foam::treeBoundBox::treeBoundBox
146 const UList<point>& points,
147 const labelUList& indices
150 boundBox(points, indices, false)
152 if (points.empty() || indices.empty())
156 "treeBoundBox::treeBoundBox"
157 "(const UList<point>&, const labelUList&)"
158 ) << "cannot find bounding box for zero-sized pointField, "
159 << "returning zero" << endl;
166 // * * * * * * * * * * * * * * * Member Functions * * * * * * * * * * * * * //
168 Foam::tmp<Foam::pointField> Foam::treeBoundBox::points() const
170 tmp<pointField> tPts = tmp<pointField>(new pointField(8));
172 pointField& points = tPts();
174 forAll(points, octant)
176 points[octant] = corner(octant);
184 Foam::treeBoundBox Foam::treeBoundBox::subBbox(const direction octant) const
186 return subBbox(midpoint(), octant);
190 // Octant to bounding box using permutation only.
191 Foam::treeBoundBox Foam::treeBoundBox::subBbox
194 const direction octant
201 "treeBoundBox::subBbox(const point&, const direction)"
202 ) << "octant should be [0..7]"
203 << abort(FatalError);
206 // start with a copy of this bounding box and adjust limits accordingly
207 treeBoundBox subBb(*this);
208 point& bbMin = subBb.min();
209 point& bbMax = subBb.max();
211 if (octant & treeBoundBox::RIGHTHALF)
213 bbMin.x() = mid.x(); // mid -> max
217 bbMax.x() = mid.x(); // min -> mid
220 if (octant & treeBoundBox::TOPHALF)
222 bbMin.y() = mid.y(); // mid -> max
226 bbMax.y() = mid.y(); // min -> mid
229 if (octant & treeBoundBox::FRONTHALF)
231 bbMin.z() = mid.z(); // mid -> max
235 bbMax.z() = mid.z(); // min -> mid
242 bool Foam::treeBoundBox::overlaps
245 const scalar radiusSqr
248 // Find out where centre is in relation to bb.
249 // Find nearest point on bb.
252 for (direction dir = 0; dir < vector::nComponents; dir++)
254 scalar d0 = min()[dir] - centre[dir];
255 scalar d1 = max()[dir] - centre[dir];
257 if ((d0 > 0) != (d1 > 0))
259 // centre inside both extrema. This component does not add any
262 else if (Foam::mag(d0) < Foam::mag(d1))
271 if (distSqr > radiusSqr)
281 // line intersection. Returns true if line (start to end) inside
282 // bb or intersects bb. Sets pt to intersection.
284 // Sutherlands algorithm:
286 // - start = intersection of line with one of the planes bounding
288 // - stop if start inside bb (return true)
289 // - stop if start and end in same 'half' (e.g. both above bb)
292 // Uses posBits to efficiently determine 'half' in which start and end
296 // - sets coordinate to exact position: e.g. pt.x() = min().x()
297 // since plane intersect routine might have truncation error.
298 // This makes sure that posBits tests 'inside'
299 bool Foam::treeBoundBox::intersects
301 const point& overallStart,
302 const vector& overallVec,
309 const direction endBits = posBits(end);
314 direction ptBits = posBits(pt);
319 ptOnFaces = faceBits(pt);
323 if ((ptBits & endBits) != 0)
325 // pt and end in same block outside of bb
326 ptOnFaces = faceBits(pt);
330 if (ptBits & LEFTBIT)
332 // Intersect with plane V=min, n=-1,0,0
333 if (Foam::mag(overallVec.x()) > VSMALL)
335 scalar s = (min().x() - overallStart.x())/overallVec.x();
337 pt.y() = overallStart.y() + overallVec.y()*s;
338 pt.z() = overallStart.z() + overallVec.z()*s;
342 // Vector not in x-direction. But still intersecting bb planes.
343 // So must be close - just snap to bb.
347 else if (ptBits & RIGHTBIT)
349 // Intersect with plane V=max, n=1,0,0
350 if (Foam::mag(overallVec.x()) > VSMALL)
352 scalar s = (max().x() - overallStart.x())/overallVec.x();
354 pt.y() = overallStart.y() + overallVec.y()*s;
355 pt.z() = overallStart.z() + overallVec.z()*s;
362 else if (ptBits & BOTTOMBIT)
364 // Intersect with plane V=min, n=0,-1,0
365 if (Foam::mag(overallVec.y()) > VSMALL)
367 scalar s = (min().y() - overallStart.y())/overallVec.y();
368 pt.x() = overallStart.x() + overallVec.x()*s;
370 pt.z() = overallStart.z() + overallVec.z()*s;
377 else if (ptBits & TOPBIT)
379 // Intersect with plane V=max, n=0,1,0
380 if (Foam::mag(overallVec.y()) > VSMALL)
382 scalar s = (max().y() - overallStart.y())/overallVec.y();
383 pt.x() = overallStart.x() + overallVec.x()*s;
385 pt.z() = overallStart.z() + overallVec.z()*s;
392 else if (ptBits & BACKBIT)
394 // Intersect with plane V=min, n=0,0,-1
395 if (Foam::mag(overallVec.z()) > VSMALL)
397 scalar s = (min().z() - overallStart.z())/overallVec.z();
398 pt.x() = overallStart.x() + overallVec.x()*s;
399 pt.y() = overallStart.y() + overallVec.y()*s;
407 else if (ptBits & FRONTBIT)
409 // Intersect with plane V=max, n=0,0,1
410 if (Foam::mag(overallVec.z()) > VSMALL)
412 scalar s = (max().z() - overallStart.z())/overallVec.z();
413 pt.x() = overallStart.x() + overallVec.x()*s;
414 pt.y() = overallStart.y() + overallVec.y()*s;
426 bool Foam::treeBoundBox::intersects
434 return intersects(start, end-start, start, end, pt, ptBits);
438 bool Foam::treeBoundBox::contains(const vector& dir, const point& pt) const
441 // Compare all components against min and max of bb
443 for (direction cmpt=0; cmpt<3; cmpt++)
445 if (pt[cmpt] < min()[cmpt])
449 else if (pt[cmpt] == min()[cmpt])
451 // On edge. Outside if direction points outwards.
458 if (pt[cmpt] > max()[cmpt])
462 else if (pt[cmpt] == max()[cmpt])
464 // On edge. Outside if direction points outwards.
472 // All components inside bb
477 // Code position of pt on bounding box faces
478 Foam::direction Foam::treeBoundBox::faceBits(const point& pt) const
480 direction faceBits = 0;
481 if (pt.x() == min().x())
485 else if (pt.x() == max().x())
487 faceBits |= RIGHTBIT;
490 if (pt.y() == min().y())
492 faceBits |= BOTTOMBIT;
494 else if (pt.y() == max().y())
499 if (pt.z() == min().z())
503 else if (pt.z() == max().z())
505 faceBits |= FRONTBIT;
511 // Code position of point relative to box
512 Foam::direction Foam::treeBoundBox::posBits(const point& pt) const
514 direction posBits = 0;
516 if (pt.x() < min().x())
520 else if (pt.x() > max().x())
525 if (pt.y() < min().y())
527 posBits |= BOTTOMBIT;
529 else if (pt.y() > max().y())
534 if (pt.z() < min().z())
538 else if (pt.z() > max().z())
546 // nearest and furthest corner coordinate.
547 // !names of treeBoundBox::min() and treeBoundBox::max() are confusing!
548 void Foam::treeBoundBox::calcExtremities
555 scalar nearX, nearY, nearZ;
556 scalar farX, farY, farZ;
558 if (Foam::mag(min().x() - pt.x()) < Foam::mag(max().x() - pt.x()))
569 if (Foam::mag(min().y() - pt.y()) < Foam::mag(max().y() - pt.y()))
580 if (Foam::mag(min().z() - pt.z()) < Foam::mag(max().z() - pt.z()))
591 nearest = point(nearX, nearY, nearZ);
592 furthest = point(farX, farY, farZ);
596 Foam::scalar Foam::treeBoundBox::maxDist(const point& pt) const
599 calcExtremities(pt, near, far);
601 return Foam::mag(far - pt);
605 // Distance comparator
606 // Compare all vertices of bounding box against all of other bounding
607 // box to see if all vertices of one are nearer
608 Foam::label Foam::treeBoundBox::distanceCmp
611 const treeBoundBox& other
615 // Distance point <-> nearest and furthest away vertex of this
618 point nearThis, farThis;
620 // get nearest and furthest away vertex
621 calcExtremities(pt, nearThis, farThis);
623 const scalar minDistThis =
624 sqr(nearThis.x() - pt.x())
625 + sqr(nearThis.y() - pt.y())
626 + sqr(nearThis.z() - pt.z());
627 const scalar maxDistThis =
628 sqr(farThis.x() - pt.x())
629 + sqr(farThis.y() - pt.y())
630 + sqr(farThis.z() - pt.z());
633 // Distance point <-> other
636 point nearOther, farOther;
638 // get nearest and furthest away vertex
639 other.calcExtremities(pt, nearOther, farOther);
641 const scalar minDistOther =
642 sqr(nearOther.x() - pt.x())
643 + sqr(nearOther.y() - pt.y())
644 + sqr(nearOther.z() - pt.z());
645 const scalar maxDistOther =
646 sqr(farOther.x() - pt.x())
647 + sqr(farOther.y() - pt.y())
648 + sqr(farOther.z() - pt.z());
653 if (maxDistThis < minDistOther)
655 // All vertices of this are nearer to point than any vertex of other
658 else if (minDistThis > maxDistOther)
660 // All vertices of this are further from point than any vertex of other
671 // * * * * * * * * * * * * * * * Friend Operators * * * * * * * * * * * * * //
673 bool Foam::operator==(const treeBoundBox& a, const treeBoundBox& b)
677 static_cast<const boundBox&>(a),
678 static_cast<const boundBox&>(b)
683 bool Foam::operator!=(const treeBoundBox& a, const treeBoundBox& b)
689 // * * * * * * * * * * * * * * * Ostream Operator * * * * * * * * * * * * * //
691 Foam::Ostream& Foam::operator<<(Ostream& os, const treeBoundBox& bb)
693 return os << static_cast<const boundBox&>(bb);
697 Foam::Istream& Foam::operator>>(Istream& is, treeBoundBox& bb)
699 return is >> static_cast<boundBox&>(bb);
703 // ************************************************************************* //