Line data Source code
1 : // The libMesh Finite Element Library.
2 : // Copyright (C) 2002-2025 Benjamin S. Kirk, John W. Peterson, Roy H. Stogner
3 :
4 : // This library is free software; you can redistribute it and/or
5 : // modify it under the terms of the GNU Lesser General Public
6 : // License as published by the Free Software Foundation; either
7 : // version 2.1 of the License, or (at your option) any later version.
8 :
9 : // This library is distributed in the hope that it will be useful,
10 : // but WITHOUT ANY WARRANTY; without even the implied warranty of
11 : // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
12 : // Lesser General Public License for more details.
13 :
14 : // You should have received a copy of the GNU Lesser General Public
15 : // License along with this library; if not, write to the Free Software
16 : // Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
17 :
18 :
19 :
20 : // Local includes
21 : #include "libmesh/bounding_box.h"
22 :
23 : // C++ includes
24 : #include <algorithm> // std::min_element
25 : #include <array>
26 :
27 : namespace libMesh
28 : {
29 : // Small helper function to make contains_point() more readable.
30 35799 : inline bool is_between(Real min, Real check, Real max)
31 : {
32 405087 : return min <= check && check <= max;
33 : }
34 :
35 141776 : bool BoundingBox::contains_point (const Point & p) const
36 : {
37 : // Make local variables first to make things more clear in a moment
38 141776 : Real my_min_x = this->first(0);
39 141776 : Real my_max_x = this->second(0);
40 141776 : bool x_int = is_between(my_min_x, p(0), my_max_x);
41 :
42 11752 : bool intersection_true = x_int;
43 :
44 : #if LIBMESH_DIM > 1
45 141776 : Real my_min_y = this->first(1);
46 141776 : Real my_max_y = this->second(1);
47 141776 : bool y_int = is_between(my_min_y, p(1), my_max_y);
48 :
49 141776 : intersection_true = intersection_true && y_int;
50 : #endif
51 :
52 :
53 : #if LIBMESH_DIM > 2
54 141776 : Real my_min_z = this->first(2);
55 141776 : Real my_max_z = this->second(2);
56 141776 : bool z_int = is_between(my_min_z, p(2), my_max_z);
57 :
58 141776 : intersection_true = intersection_true && z_int;
59 : #endif
60 :
61 141776 : return intersection_true;
62 : }
63 :
64 :
65 :
66 2172 : Real BoundingBox::max_size() const
67 : {
68 2172 : Real size = 0;
69 8688 : for (unsigned int d = 0; d != LIBMESH_DIM; ++d)
70 : {
71 6516 : Real sized = this->second(d) - this->first(d);
72 7059 : if (!libmesh_isinf(sized) &&
73 13032 : this->second(d) != std::numeric_limits<Real>::max() &&
74 543 : this->first(d) != -std::numeric_limits<Real>::max())
75 6516 : size = std::max(size, sized);
76 : }
77 2172 : return size;
78 : }
79 :
80 :
81 :
82 2172 : bool BoundingBox::contains_point
83 : (const Point & p, Real abs_tol, Real rel_tol) const
84 : {
85 181 : libmesh_assert_greater_equal(abs_tol, Real(0));
86 181 : libmesh_assert_greater_equal(rel_tol, Real(0));
87 :
88 : // Just use the other contains_point overload
89 181 : libmesh_assert_greater(rel_tol+abs_tol, Real(0));
90 :
91 : // Find absolute tolerance from relative tolerance
92 2172 : const Real tol = std::max(abs_tol, this->max_size()*rel_tol);
93 :
94 : // Make local variables first to make things more clear in a moment
95 2172 : const Real my_min_x = this->first(0) - tol;
96 2172 : const Real my_max_x = this->second(0) + tol;
97 2172 : const bool x_int = is_between(my_min_x, p(0), my_max_x);
98 :
99 181 : bool intersection_true = x_int;
100 :
101 : #if LIBMESH_DIM > 1
102 2172 : const Real my_min_y = this->first(1) - tol;
103 2172 : const Real my_max_y = this->second(1) + tol;
104 2172 : const bool y_int = is_between(my_min_y, p(1), my_max_y);
105 :
106 2172 : intersection_true = intersection_true && y_int;
107 : #endif
108 :
109 :
110 : #if LIBMESH_DIM > 2
111 2172 : const Real my_min_z = this->first(2) - tol;
112 2172 : const Real my_max_z = this->second(2) + tol;
113 2172 : const bool z_int = is_between(my_min_z, p(2), my_max_z);
114 :
115 2172 : intersection_true = intersection_true && z_int;
116 : #endif
117 :
118 2172 : return intersection_true;
119 : }
120 :
121 :
122 :
123 0 : void BoundingBox::intersect_with (const BoundingBox & other_box)
124 : {
125 0 : this->first(0) = std::max(this->first(0), other_box.first(0));
126 0 : this->second(0) = std::min(this->second(0), other_box.second(0));
127 :
128 : #if LIBMESH_DIM > 1
129 0 : this->first(1) = std::max(this->first(1), other_box.first(1));
130 0 : this->second(1) = std::min(this->second(1), other_box.second(1));
131 : #endif
132 :
133 : #if LIBMESH_DIM > 2
134 0 : this->first(2) = std::max(this->first(2), other_box.first(2));
135 0 : this->second(2) = std::min(this->second(2), other_box.second(2));
136 : #endif
137 0 : }
138 :
139 :
140 63996743 : void BoundingBox::union_with (const BoundingBox & other_box)
141 : {
142 63996743 : this->first(0) = std::min(this->first(0), other_box.first(0));
143 63996743 : this->second(0) = std::max(this->second(0), other_box.second(0));
144 :
145 : #if LIBMESH_DIM > 1
146 63996743 : this->first(1) = std::min(this->first(1), other_box.first(1));
147 63996743 : this->second(1) = std::max(this->second(1), other_box.second(1));
148 : #endif
149 :
150 : #if LIBMESH_DIM > 2
151 63996743 : this->first(2) = std::min(this->first(2), other_box.first(2));
152 63996743 : this->second(2) = std::max(this->second(2), other_box.second(2));
153 : #endif
154 63996743 : }
155 :
156 :
157 :
158 1136 : Real BoundingBox::signed_distance(const Point & p) const
159 : {
160 1136 : if (contains_point(p))
161 : {
162 : // Sign convention: if Point is inside the bbox, the distance is
163 : // negative. We then find the smallest distance to the different
164 : // sides of the box and return that.
165 426 : Real min_dist = std::numeric_limits<Real>::max();
166 :
167 1704 : for (unsigned int dir=0; dir<LIBMESH_DIM; ++dir)
168 : {
169 1314 : min_dist = std::min(min_dist, std::abs(p(dir) - second(dir)));
170 1452 : min_dist = std::min(min_dist, std::abs(p(dir) - first(dir)));
171 : }
172 :
173 426 : return -min_dist;
174 : }
175 : else // p is outside the box
176 : {
177 710 : Real dx[3] = {0., 0., 0.};
178 :
179 : // Compute distance "above"/"below" the box in each
180 : // direction. If the point is somewhere in between the (min,
181 : // max) values of the box, dx is 0.
182 2840 : for (unsigned int dir=0; dir<LIBMESH_DIM; ++dir)
183 : {
184 2130 : if (p(dir) > second(dir))
185 639 : dx[dir] = p(dir) - second(dir);
186 1491 : else if (p(dir) < first(dir))
187 639 : dx[dir] = p(dir) - first(dir);
188 : }
189 :
190 710 : return std::sqrt(dx[0]*dx[0] + dx[1]*dx[1] + dx[2]*dx[2]);
191 : }
192 : }
193 :
194 :
195 11265 : void BoundingBox::scale(const Real factor)
196 : {
197 : Real append;
198 45060 : for (unsigned int dim = 0; dim != LIBMESH_DIM; ++dim)
199 : {
200 36627 : if (this->first(dim) != std::numeric_limits<Real>::max() &&
201 33795 : this->second(dim) != -std::numeric_limits<Real>::max())
202 : {
203 2832 : libmesh_assert_greater_equal(this->second(dim), this->first(dim));
204 33795 : append = (this->second(dim) - this->first(dim)) * factor;
205 33795 : this->first(dim) -= append;
206 33795 : this->second(dim) += append;
207 : }
208 : }
209 11265 : }
210 :
211 :
212 12 : void BoundingBox::print(std::ostream & os) const
213 : {
214 13 : os << "(min=" << this->min() << ", max=" << this->max() << ")";
215 12 : }
216 :
217 : } // namespace libMesh
|