deal.II version GIT relicensing-6834-g5b78e6bcdf 2026-10-01 11:20:01+00:00
\(\newcommand{\dealvcentcolon}{\mathrel{\mathop{:}}}\) \(\newcommand{\dealcoloneq}{\dealvcentcolon\mathrel{\mkern-1.2mu}=}\) \(\newcommand{\jump}[1]{\left[\!\left[ #1 \right]\!\right]}\) \(\newcommand{\average}[1]{\left\{\!\left\{ #1 \right\}\!\right\}}\)
Loading...
Searching...
No Matches
bounding_box.cc
Go to the documentation of this file.
1// -----------------------------------------------------------------------------
2//
3// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception OR LGPL-2.1-or-later
4// Copyright (C) 2017 - 2025 by the deal.II authors
5//
6// This file is part of the deal.II library.
7//
8// Detailed license information governing the source code and contributions
9// can be found in LICENSE.md and CONTRIBUTING.md at the top level directory.
10//
11// -----------------------------------------------------------------------------
12
15
16#include <limits>
17#include <numeric>
18
20
21template <int spacedim, typename Number>
22bool
24 const double tolerance) const
25{
26 for (unsigned int i = 0; i < spacedim; ++i)
27 {
28 // Bottom left-top right convention: the point is outside if it's smaller
29 // than the first or bigger than the second boundary point The bounding
30 // box is defined as a closed set
31 if ((p[i] <
32 this->boundary_points.first[i] - tolerance * side_length(i)) ||
33 (p[i] > this->boundary_points.second[i] + tolerance * side_length(i)))
34 return false;
35 }
36 return true;
37}
38
39
40
41template <int spacedim, typename Number>
42void
44 const BoundingBox<spacedim, Number> &other_bbox)
45{
46 for (unsigned int i = 0; i < spacedim; ++i)
47 {
48 this->boundary_points.first[i] =
49 std::min(this->boundary_points.first[i],
50 other_bbox.boundary_points.first[i]);
51 this->boundary_points.second[i] =
52 std::max(this->boundary_points.second[i],
53 other_bbox.boundary_points.second[i]);
54 }
55}
56
57template <int spacedim, typename Number>
58bool
60 const BoundingBox<spacedim, Number> &other_bbox,
61 const double tolerance) const
62{
63 for (unsigned int i = 0; i < spacedim; ++i)
64 {
65 // testing if the boxes are close enough to intersect
66 if ((other_bbox.boundary_points.second[i] <
67 this->boundary_points.first[i] - tolerance * side_length(i)) ||
68 (other_bbox.boundary_points.first[i] >
69 this->boundary_points.second[i] + tolerance * side_length(i)))
70 return false;
71 }
72 return true;
73}
74
75template <int spacedim, typename Number>
78 const BoundingBox<spacedim, Number> &other_bbox,
79 const double tolerance) const
80{
81 if (!has_overlap_with(other_bbox, tolerance))
83
84 if (spacedim == 1)
85 {
86 // In dimension 1 if the two bounding box are neighbors
87 // we can merge them
89 }
90 else
91 {
92 const std::array<Point<spacedim, Number>, 2> bbox1 = {
93 {this->get_boundary_points().first,
94 this->get_boundary_points().second}};
95 const std::array<Point<spacedim, Number>, 2> bbox2 = {
96 {other_bbox.get_boundary_points().first,
97 other_bbox.get_boundary_points().second}};
98
99 // The boxes intersect: we need to understand now how they intersect.
100 // We begin by computing the intersection:
101 std::array<double, spacedim> intersect_bbox_min;
102 std::array<double, spacedim> intersect_bbox_max;
103 for (unsigned int d = 0; d < spacedim; ++d)
104 {
105 intersect_bbox_min[d] = std::max(bbox1[0][d], bbox2[0][d]);
106 intersect_bbox_max[d] = std::min(bbox1[1][d], bbox2[1][d]);
107 }
108
109 // Finding the intersection's dimension
110 int intersect_dim = spacedim;
111 for (unsigned int d = 0; d < spacedim; ++d)
112 if (std::abs(intersect_bbox_min[d] - intersect_bbox_max[d]) <=
113 tolerance * (std::abs(intersect_bbox_min[d]) +
114 std::abs(intersect_bbox_max[d])))
115 --intersect_dim;
116
117 if (intersect_dim == 0 || intersect_dim == spacedim - 2)
119
120 // Checking the two mergeable cases: first if the boxes are aligned so
121 // that they can be merged
122 unsigned int not_align_1 = 0, not_align_2 = 0;
123 bool same_direction = true;
124 for (unsigned int d = 0; d < spacedim; ++d)
125 {
126 if (std::abs(bbox2[0][d] - bbox1[0][d]) >
127 tolerance * (std::abs(bbox2[0][d]) + std::abs(bbox1[0][d])))
128 ++not_align_1;
129 if (std::abs(bbox1[1][d] - bbox2[1][d]) >
130 tolerance * (std::abs(bbox1[1][d]) + std::abs(bbox2[1][d])))
131 ++not_align_2;
132 if (not_align_1 != not_align_2)
133 {
134 same_direction = false;
135 break;
136 }
137 }
138
139 if (not_align_1 <= 1 && not_align_2 <= 1 && same_direction)
141
142 // Second: one box is contained/equal to the other
143 if ((this->point_inside(bbox2[0]) && this->point_inside(bbox2[1])) ||
144 (other_bbox.point_inside(bbox1[0], tolerance) &&
145 other_bbox.point_inside(bbox1[1], tolerance)))
147
148 // Degenerate and mergeable cases have been found, it remains:
150 }
151}
152
153
154
155template <int spacedim, typename Number>
156double
158{
159 double vol = 1.0;
160 for (unsigned int i = 0; i < spacedim; ++i)
161 vol *= (this->boundary_points.second[i] - this->boundary_points.first[i]);
162 return vol;
163}
164
165
166
167template <int spacedim, typename Number>
168Number
169BoundingBox<spacedim, Number>::lower_bound(const unsigned int direction) const
170{
171 AssertIndexRange(direction, spacedim);
172
173 return boundary_points.first[direction];
174}
175
176
177
178template <int spacedim, typename Number>
179Number
180BoundingBox<spacedim, Number>::upper_bound(const unsigned int direction) const
181{
182 AssertIndexRange(direction, spacedim);
183
184 return boundary_points.second[direction];
185}
186
187
188
189template <int spacedim, typename Number>
192{
194 for (unsigned int i = 0; i < spacedim; ++i)
195 point[i] = .5 * (boundary_points.first[i] + boundary_points.second[i]);
196
197 return point;
198}
199
200
201
202template <int spacedim, typename Number>
204BoundingBox<spacedim, Number>::bounds(const unsigned int direction) const
205{
206 AssertIndexRange(direction, spacedim);
207
208 std::pair<Point<1, Number>, Point<1, Number>> lower_upper_bounds;
209 lower_upper_bounds.first[0] = lower_bound(direction);
210 lower_upper_bounds.second[0] = upper_bound(direction);
211
212 return BoundingBox<1, Number>(lower_upper_bounds);
213}
214
215
216
217template <int spacedim, typename Number>
218Number
219BoundingBox<spacedim, Number>::side_length(const unsigned int direction) const
220{
221 AssertIndexRange(direction, spacedim);
222
223 return boundary_points.second[direction] - boundary_points.first[direction];
224}
225
227
228template <int spacedim, typename Number>
230BoundingBox<spacedim, Number>::vertex(const unsigned int index) const
231{
233
234 const Point<spacedim> unit_cell_vertex =
238 for (unsigned int i = 0; i < spacedim; ++i)
239 point[i] = boundary_points.first[i] + side_length(i) * unit_cell_vertex[i];
240
241 return point;
242}
243
244
246template <int spacedim, typename Number>
248BoundingBox<spacedim, Number>::child(const unsigned int index) const
249{
251
252 // Vertex closest to child.
253 const Point<spacedim, Number> parent_vertex = vertex(index);
254 const Point<spacedim, Number> parent_center = center();
255
256 const Point<spacedim> upper_corner_unit_cell =
259
260 const Point<spacedim> lower_corner_unit_cell =
262
263 std::pair<Point<spacedim, Number>, Point<spacedim, Number>>
264 child_lower_upper_corner;
265 for (unsigned int i = 0; i < spacedim; ++i)
266 {
267 const double child_side_length = side_length(i) / 2;
268
269 const double child_center = (parent_center[i] + parent_vertex[i]) / 2;
270
271 child_lower_upper_corner.first[i] =
272 child_center + child_side_length * (lower_corner_unit_cell[i] - .5);
273 child_lower_upper_corner.second[i] =
274 child_center + child_side_length * (upper_corner_unit_cell[i] - .5);
275 }
276
277 return BoundingBox<spacedim, Number>(child_lower_upper_corner);
278}
279
280
281
282template <int spacedim, typename Number>
283BoundingBox<spacedim - 1, Number>
284BoundingBox<spacedim, Number>::cross_section(const unsigned int direction) const
285{
286 AssertIndexRange(direction, spacedim);
287
288 std::pair<Point<spacedim - 1, Number>, Point<spacedim - 1, Number>>
289 cross_section_lower_upper_corner;
290 for (unsigned int d = 0; d < spacedim - 1; ++d)
291 {
292 const int index_to_write_from =
293 internal::coordinate_to_one_dim_higher<spacedim - 1>(direction, d);
294
295 cross_section_lower_upper_corner.first[d] =
296 boundary_points.first[index_to_write_from];
297
298 cross_section_lower_upper_corner.second[d] =
299 boundary_points.second[index_to_write_from];
300 }
302 return BoundingBox<spacedim - 1, Number>(cross_section_lower_upper_corner);
303}
304
305
306
307template <int spacedim, typename Number>
310 const Point<spacedim, Number> &point) const
311{
312 auto unit = point;
313 const auto diag = boundary_points.second - boundary_points.first;
314 unit -= boundary_points.first;
315 for (unsigned int d = 0; d < spacedim; ++d)
316 unit[d] /= diag[d];
317 return unit;
318}
320
321
322template <int spacedim, typename Number>
325 const Point<spacedim, Number> &point) const
327 auto real = boundary_points.first;
328 const auto diag = boundary_points.second - boundary_points.first;
329 for (unsigned int d = 0; d < spacedim; ++d)
330 real[d] += diag[d] * point[d];
331 return real;
332}
334
335
336template <int spacedim, typename Number>
337Number
339 const Point<spacedim, Number> &point,
340 const unsigned int direction) const
341{
342 const Number p1 = lower_bound(direction);
343 const Number p2 = upper_bound(direction);
344
345 if (point[direction] > p2)
346 return point[direction] - p2;
347 else if (point[direction] < p1)
348 return p1 - point[direction];
349 else
350 return -std::min(point[direction] - p1, p2 - point[direction]);
351}
352
353
355template <int spacedim, typename Number>
356Number
358 const Point<spacedim, Number> &point) const
359{
360 // calculate vector of orthogonal signed distances
361 std::array<Number, spacedim> distances;
362 for (unsigned int d = 0; d < spacedim; ++d)
363 distances[d] = signed_distance(point, d);
364
365 // determine the number of positive signed distances
366 const unsigned int n_positive_signed_distances =
367 std::count_if(distances.begin(), distances.end(), [](const auto &a) {
368 return a > 0.0;
369 });
370
371 if (n_positive_signed_distances <= 1)
372 // point is inside of bounding box (0: all signed distances are
373 // negative; find the index with the smallest absolute value)
374 // or next to a face (1: all signed distances are negative
375 // but one; find this index)
376 return *std::max_element(distances.begin(), distances.end());
377 else
378 // point is next to a corner (2D/3D: all signed distances are
379 // positive) or a line (3D: all signed distances are positive
380 // but one) -> take the l2-norm of all positive signed distances
381 return std::sqrt(std::accumulate(distances.begin(),
382 distances.end(),
383 0.0,
384 [](const auto &a, const auto &b) {
385 return a + (b > 0 ? b * b : 0.0);
386 }));
387}
388
389
390
391template <int dim, typename Number>
394{
395 std::pair<Point<dim, Number>, Point<dim, Number>> lower_upper_corner;
396 for (unsigned int i = 0; i < dim; ++i)
397 {
398 lower_upper_corner.second[i] = 1;
399 }
400 return BoundingBox<dim, Number>(lower_upper_corner);
401}
402
403
404#include "base/bounding_box.inst"
NeighborType
BoundingBox< dim, Number > create_unit_bounding_box()
std::pair< Point< spacedim, Number >, Point< spacedim, Number > > boundary_points
BoundingBox< 1, Number > bounds(const unsigned int direction) const
bool has_overlap_with(const BoundingBox< spacedim, Number > &other_bbox, const double tolerance=std::numeric_limits< Number >::epsilon()) const
Point< spacedim, Number > center() const
Number lower_bound(const unsigned int direction) const
Number signed_distance(const Point< spacedim, Number > &point, const unsigned int direction) const
void merge_with(const BoundingBox< spacedim, Number > &other_bbox)
std::pair< Point< spacedim, Number >, Point< spacedim, Number > > & get_boundary_points()
bool point_inside(const Point< spacedim, Number > &p, const double tolerance=std::numeric_limits< Number >::epsilon()) const
double volume() const
Point< spacedim, Number > real_to_unit(const Point< spacedim, Number > &point) const
Number side_length(const unsigned int direction) const
BoundingBox< spacedim, Number > child(const unsigned int index) const
NeighborType get_neighbor_type(const BoundingBox< spacedim, Number > &other_bbox, const double tolerance=std::numeric_limits< Number >::epsilon()) const
Point< spacedim, Number > vertex(const unsigned int index) const
BoundingBox< spacedim - 1, Number > cross_section(const unsigned int direction) const
Number upper_bound(const unsigned int direction) const
Point< spacedim, Number > unit_to_real(const Point< spacedim, Number > &point) const
Definition point.h:111
#define DEAL_II_NAMESPACE_OPEN
Definition config.h:38
#define DEAL_II_NAMESPACE_CLOSE
Definition config.h:39
#define AssertIndexRange(index, range)
::VectorizedArray< Number, width > min(const ::VectorizedArray< Number, width > &, const ::VectorizedArray< Number, width > &)
::VectorizedArray< Number, width > max(const ::VectorizedArray< Number, width > &, const ::VectorizedArray< Number, width > &)
::VectorizedArray< Number, width > sqrt(const ::VectorizedArray< Number, width > &)
::VectorizedArray< Number, width > abs(const ::VectorizedArray< Number, width > &)
static Point< dim > unit_cell_vertex(const unsigned int vertex)