version 3.11-dev
Loading...
Searching...
No Matches
boundingboxtree.hh
Go to the documentation of this file.
1// -*- mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*-
2// vi: set et ts=4 sw=4 sts=4:
3//
4// SPDX-FileCopyrightText: Copyright © DuMux Project contributors, see AUTHORS.md in root folder
5// SPDX-License-Identifier: GPL-3.0-or-later
6//
19#ifndef DUMUX_GEOMETRY_BOUNDINGBOXTREE_HH
20#define DUMUX_GEOMETRY_BOUNDINGBOXTREE_HH
21
22#include <vector>
23#include <array>
24#include <algorithm>
25#include <memory>
26#include <numeric>
27#include <limits>
28#include <type_traits>
29#include <iostream>
30
31#include <dune/common/promotiontraits.hh>
32#include <dune/common/fvector.hh>
33
34#ifndef DOXYGEN
35namespace Dumux::Detail {
36
37template<typename ctype>
38inline constexpr ctype minimumBaseEpsilon = 10.0*std::numeric_limits<ctype>::epsilon();
39
40} // namespace Dumux::Detail
41#endif // DOXYGEN
42
43namespace Dumux {
44
49template <int dimworld, class ctype, class Geometry>
50 requires requires(const Geometry& g) { g.corner(0); g.corners(); }
51inline void computeGeometryBoundingBox(ctype* b, const Geometry& geometry)
52{
53 // get the bounding box coordinates
54 ctype* xMin = b;
55 ctype* xMax = b + dimworld;
56
57 // Get coordinates of first vertex
58 auto corner = geometry.corner(0);
59 for (std::size_t dimIdx = 0; dimIdx < dimworld; ++dimIdx)
60 xMin[dimIdx] = xMax[dimIdx] = corner[dimIdx];
61
62 // Compute the min and max over the remaining vertices
63 for (std::size_t cornerIdx = 1; cornerIdx < geometry.corners(); ++cornerIdx)
64 {
65 corner = geometry.corner(cornerIdx);
66 for (std::size_t dimIdx = 0; dimIdx < dimworld; ++dimIdx)
67 {
68 using std::max;
69 using std::min;
70 xMin[dimIdx] = min(xMin[dimIdx], corner[dimIdx]);
71 xMax[dimIdx] = max(xMax[dimIdx], corner[dimIdx]);
72 }
73 }
74}
75
80template <int dimworld, class ctype, class Entity>
81 requires requires(const Entity& e) { e.geometry(); }
82inline void computeEntityBoundingBox(ctype* b, const Entity& entity)
83{ computeGeometryBoundingBox<dimworld>(b, entity.geometry()); }
84
103template <class GeometricEntitySet>
105{
106 static constexpr int dimworld = GeometricEntitySet::dimensionworld;
107 using ctype = typename GeometricEntitySet::ctype;
108
114 struct BoundingBoxNode
115 {
116 std::size_t child0;
117 std::size_t child1;
118 };
119
120public:
122 using EntitySet = GeometricEntitySet;
123
125 BoundingBoxTree() = default;
126
128 explicit BoundingBoxTree(std::shared_ptr<const GeometricEntitySet> set)
129 { build(set); }
130
132 void build(std::shared_ptr<const GeometricEntitySet> set)
133 {
134 // set the pointer to the entity set
135 entitySet_ = set;
136
137 // clear all internal data
138 boundingBoxNodes_.clear();
139 boundingBoxCoordinates_.clear();
140
141 // Create bounding boxes for all elements
142 const auto numLeaves = set->size();
143
144 // reserve enough space for the nodes and the coordinates
145 const auto numNodes = 2*numLeaves - 1;
146 boundingBoxNodes_.reserve(numNodes);
147 boundingBoxCoordinates_.reserve(numNodes*2*dimworld);
148
149 // create a vector for leaf boxes (min and max for all dims)
150 std::vector<ctype> leafBoxes(2*dimworld*numLeaves);
151
152 for (const auto& geometricEntity : *set)
153 computeEntityBoundingBox<dimworld>(leafBoxes.data() + 2*dimworld*set->index(geometricEntity), geometricEntity);
154
155 // create the leaf partition, the set of available indices (to be sorted)
156 std::vector<std::size_t> leafPartition(numLeaves);
157 std::iota(leafPartition.begin(), leafPartition.end(), 0);
158
159 // Recursively build the bounding box tree
160 build_(leafBoxes, leafPartition.begin(), leafPartition.end());
161 }
162
164 const EntitySet& entitySet() const
165 { return *entitySet_; }
166
170
172 const BoundingBoxNode& getBoundingBoxNode(std::size_t nodeIdx) const
173 { return boundingBoxNodes_[nodeIdx]; }
174
176 const ctype* getBoundingBoxCoordinates(std::size_t nodeIdx) const
177 { return boundingBoxCoordinates_.data() + 2*dimworld*nodeIdx; }
178
180 std::size_t numBoundingBoxes() const
181 { return boundingBoxNodes_.size(); }
182
185 bool isLeaf(const BoundingBoxNode& node, std::size_t nodeIdx) const
186 { return node.child0 == nodeIdx; }
187
188private:
189
191 std::vector<BoundingBoxNode> boundingBoxNodes_;
192
194 std::vector<ctype> boundingBoxCoordinates_;
195
197 std::shared_ptr<const EntitySet> entitySet_;
198
200 std::size_t build_(const std::vector<ctype>& leafBoxes,
201 const std::vector<std::size_t>::iterator& begin,
202 const std::vector<std::size_t>::iterator& end)
203 {
204 assert(begin < end);
205
206 // If we reached the end of the recursion, i.e. only a leaf box is left
207 if (end - begin == 1)
208 {
209 // Get the bounding box coordinates for the leaf
210 const std::size_t leafNodeIdx = *begin;
211 const auto beginCoords = leafBoxes.begin() + 2*dimworld*leafNodeIdx;
212 const auto endCoords = beginCoords + 2*dimworld;
213
214 // Store the data in the bounding box
215 // leaf nodes are indicated by setting child0 to
216 // the node itself and child1 to the index of the entity in the bounding box.
217 return addBoundingBox_(BoundingBoxNode{numBoundingBoxes(), leafNodeIdx}, beginCoords, endCoords);
218 }
219
220 // Compute the bounding box of all bounding boxes in the range [begin, end]
221 const auto bCoords = computeBBoxOfBBoxes_(leafBoxes, begin, end);
222
223 // sort bounding boxes along the longest axis
224 const auto axis = computeLongestAxis_(bCoords);
225
226 // nth_element sorts the range to make sure that middle points to the coordinate median in axis direction
227 // this is the most expensive part of the algorithm
228 auto middle = begin + (end - begin)/2;
229 std::nth_element(begin, middle, end, [&leafBoxes, axis](std::size_t i, std::size_t j)
230 {
231 const ctype* bi = leafBoxes.data() + 2*dimworld*i;
232 const ctype* bj = leafBoxes.data() + 2*dimworld*j;
233 return bi[axis] + bi[axis + dimworld] < bj[axis] + bj[axis + dimworld];
234 });
235
236 // split the bounding boxes into two at the middle iterator and call build recursively, each
237 // call resulting in a new node of this bounding box, i.e. the root will be added at the end of the process.
238 return addBoundingBox_(BoundingBoxNode{build_(leafBoxes, begin, middle), build_(leafBoxes, middle, end)},
239 bCoords.begin(), bCoords.end());
240 }
241
243 template <class Iterator>
244 std::size_t addBoundingBox_(BoundingBoxNode&& node,
245 const Iterator& coordBegin,
246 const Iterator& coordEnd)
247 {
248 // Add the bounding box
249 boundingBoxNodes_.emplace_back(node);
250
251 // Add the bounding box's coordinates
252 boundingBoxCoordinates_.insert(boundingBoxCoordinates_.end(), coordBegin, coordEnd);
253
254 // return the index of the new node
255 return boundingBoxNodes_.size() - 1;
256 }
257
259 std::array<ctype, 2*dimworld>
260 computeBBoxOfBBoxes_(const std::vector<ctype>& leafBoxes,
261 const std::vector<std::size_t>::iterator& begin,
262 const std::vector<std::size_t>::iterator& end)
263 {
264 std::array<ctype, 2*dimworld> bBoxCoords;
265
266 // copy the iterator and get coordinates of first box
267 auto it = begin;
268 const auto* bFirst = leafBoxes.data() + 2*dimworld*(*it);
269
270 for (int coordIdx = 0; coordIdx < 2*dimworld; ++coordIdx)
271 bBoxCoords[coordIdx] = bFirst[coordIdx];
272
273 // Compute min and max with the remaining boxes
274 for (; it != end; ++it)
275 {
276 const auto* b = leafBoxes.data() + 2*dimworld*(*it);
277 for (int coordIdx = 0; coordIdx < dimworld; ++coordIdx)
278 if (b[coordIdx] < bBoxCoords[coordIdx])
279 bBoxCoords[coordIdx] = b[coordIdx];
280 for (int coordIdx = dimworld; coordIdx < 2*dimworld; ++coordIdx)
281 if (b[coordIdx] > bBoxCoords[coordIdx])
282 bBoxCoords[coordIdx] = b[coordIdx];
283 }
284
285 return bBoxCoords;
286 }
287
289 std::size_t computeLongestAxis_(const std::array<ctype, 2*dimworld>& bCoords)
290 {
291 std::array<ctype, dimworld> axisLength;
292 for (int coordIdx = 0; coordIdx < dimworld; ++coordIdx)
293 axisLength[coordIdx] = bCoords[dimworld + coordIdx] - bCoords[coordIdx];
294
295 return std::distance(axisLength.begin(), std::max_element(axisLength.begin(), axisLength.end()));
296 }
297};
298
304template<class ctype, int dimworld, typename std::enable_if_t<dimworld == 3, int> = 0>
305inline bool intersectsPointBoundingBox(const Dune::FieldVector<ctype, dimworld>& point, const ctype* b)
306{
307 static constexpr ctype eps_ = 1.0e-7;
308
309 using std::max;
310 const auto dx = b[3] - b[0];
311 const auto dy = b[4] - b[1];
312 const auto dz = b[5] - b[2];
313 const ctype eps = max({dx, dy, dz})*eps_;
314 return (b[0] - eps <= point[0] && point[0] <= b[3] + eps &&
315 b[1] - eps <= point[1] && point[1] <= b[4] + eps &&
316 b[2] - eps <= point[2] && point[2] <= b[5] + eps);
317}
318
324template<class ctype, int dimworld, typename std::enable_if_t<dimworld == 2, int> = 0>
325inline bool intersectsPointBoundingBox(const Dune::FieldVector<ctype, dimworld>& point, const ctype* b)
326{
327 static constexpr ctype eps_ = 1.0e-7;
328
329 using std::max;
330 const auto dx = b[2] - b[0];
331 const auto dy = b[3] - b[1];
332 const ctype eps = max(dx, dy)*eps_;
333 return (b[0] - eps <= point[0] && point[0] <= b[2] + eps &&
334 b[1] - eps <= point[1] && point[1] <= b[3] + eps);
335}
336
342template<class ctype, int dimworld, typename std::enable_if_t<dimworld == 1, int> = 0>
343inline bool intersectsPointBoundingBox(const Dune::FieldVector<ctype, dimworld>& point, const ctype* b)
344{
345 static constexpr ctype eps_ = 1.0e-7;
346 const ctype eps0 = eps_*(b[1] - b[0]);
347 return b[0] - eps0 <= point[0] && point[0] <= b[1] + eps0;
348}
349
355template<class ctype, int dimworld>
356inline bool intersectsPointBoundingBox(const Dune::FieldVector<ctype, dimworld>& point,
357 const Dune::FieldVector<ctype, dimworld>& min,
358 const Dune::FieldVector<ctype, dimworld>& max)
359{
360 std::array<ctype, 2*dimworld> bBox;
361 std::copy(min.begin(), min.end(), bBox.begin());
362 std::copy(max.begin(), max.end(), bBox.begin()+dimworld);
363 return intersectsPointBoundingBox(point, bBox.data());
364}
365
371template<int dimworld, class ctypea, class ctypeb, typename std::enable_if_t<dimworld == 3, int> = 0>
372inline bool intersectsBoundingBoxBoundingBox(const ctypea* a, const ctypeb* b)
373{
374 using ctype = typename Dune::PromotionTraits<ctypea, ctypeb>::PromotedType;
375 static constexpr ctype eps_ = 1.0e-7;
376 const ctype scale0 = std::max(b[3]-b[0], a[3]-a[0]);
377 const ctype scale1 = std::max(b[4]-b[1], a[4]-a[1]);
378 const ctype scale2 = std::max(b[5]-b[2], a[5]-a[2]);
379 const ctype maxScale = std::max(scale0, std::max(scale1, scale2));
380 const ctype minEps = maxScale*Detail::minimumBaseEpsilon<ctype>;
381 const ctype eps0 = std::max(eps_*scale0, minEps);
382 const ctype eps1 = std::max(eps_*scale1, minEps);
383 const ctype eps2 = std::max(eps_*scale2, minEps);
384 return (b[0] - eps0 <= a[3] && a[0] <= b[3] + eps0 &&
385 b[1] - eps1 <= a[4] && a[1] <= b[4] + eps1 &&
386 b[2] - eps2 <= a[5] && a[2] <= b[5] + eps2);
387
388}
389
395template<int dimworld, class ctypea, class ctypeb, typename std::enable_if_t<dimworld == 2, int> = 0>
396inline bool intersectsBoundingBoxBoundingBox(const ctypea* a, const ctypeb* b)
397{
398 using ctype = typename Dune::PromotionTraits<ctypea, ctypeb>::PromotedType;
399 static constexpr ctype eps_ = 1.0e-7;
400 const ctype scale0 = std::max(b[2]-b[0], a[2]-a[0]);
401 const ctype scale1 = std::max(b[3]-b[1], a[3]-a[1]);
402 const ctype maxScale = std::max(scale0, scale1);
403 const ctype minEps = maxScale*Detail::minimumBaseEpsilon<ctype>;
404 const ctype eps0 = std::max(eps_*scale0, minEps);
405 const ctype eps1 = std::max(eps_*scale1, minEps);
406 return (b[0] - eps0 <= a[2] && a[0] <= b[2] + eps0 &&
407 b[1] - eps1 <= a[3] && a[1] <= b[3] + eps1);
408}
409
415template<int dimworld, class ctypea, class ctypeb, typename std::enable_if_t<dimworld == 1, int> = 0>
416inline bool intersectsBoundingBoxBoundingBox(const ctypea* a, const ctypeb* b)
417{
418 using ctype = typename Dune::PromotionTraits<ctypea, ctypeb>::PromotedType;
419 static constexpr ctype eps_ = 1.0e-7;
420 const ctype scale0 = std::max(b[1]-b[0], a[1]-a[0]);
421 const ctype eps0 = std::max(eps_*scale0, Detail::minimumBaseEpsilon<ctype>*scale0);
422 return b[0] - eps0 <= a[1] && a[0] <= b[1] + eps0;
423}
424
430template<int dimworld, class ctype>
431inline ctype squaredDistancePointBoundingBox(const Dune::FieldVector<ctype, dimworld>& point, const ctype* b)
432{
433 ctype squaredDistance = 0.0;
434 for (int d = 0; d < dimworld; ++d)
435 {
436 if (point[d] < b[d])
437 squaredDistance += (point[d] - b[d])*(point[d] - b[d]);
438 if (point[d] > b[d+dimworld])
439 squaredDistance += (point[d] - b[d+dimworld])*(point[d] - b[d+dimworld]);
440 }
441 return squaredDistance;
442}
443
444} // end namespace Dumux
445
446#endif
BoundingBoxTree()=default
Default Constructor.
const ctype * getBoundingBoxCoordinates(std::size_t nodeIdx) const
Get an existing bounding box for a given node.
Definition boundingboxtree.hh:176
bool isLeaf(const BoundingBoxNode &node, std::size_t nodeIdx) const
Definition boundingboxtree.hh:185
const EntitySet & entitySet() const
the entity set this tree was built with
Definition boundingboxtree.hh:164
ElementSet EntitySet
Definition boundingboxtree.hh:122
void build(std::shared_ptr< const GeometricEntitySet > set)
Build up bounding box tree for a grid with leafGridView.
Definition boundingboxtree.hh:132
BoundingBoxTree(std::shared_ptr< const GeometricEntitySet > set)
Constructor with gridView.
Definition boundingboxtree.hh:128
std::size_t numBoundingBoxes() const
Get the number of bounding boxes currently in the tree.
Definition boundingboxtree.hh:180
const BoundingBoxNode & getBoundingBoxNode(std::size_t nodeIdx) const
Interface to be used by other bounding box trees.
Definition boundingboxtree.hh:172
static ctype squaredDistance(const Dune::FieldVector< ctype, dimWorld > &a, const Dune::FieldVector< ctype, dimWorld > &b)
Compute the shortest squared distance between two points.
Definition distance.hh:291
void computeGeometryBoundingBox(ctype *b, const Geometry &geometry)
Compute the bounding box of a geometry.
Definition boundingboxtree.hh:51
void computeEntityBoundingBox(ctype *b, const Entity &entity)
Compute the bounding box of a geometric entity.
Definition boundingboxtree.hh:82
constexpr BJ bj
Tag for the Beavers-Joseph slip condition.
Definition momentum/slipcondition.hh:42
Definition cvfelocalresidual.hh:25
Definition adapt.hh:17
bool intersectsBoundingBoxBoundingBox(const ctypea *a, const ctypeb *b)
Check whether a bounding box is intersecting another bounding box (dimworld == 3).
Definition boundingboxtree.hh:372
ctype squaredDistancePointBoundingBox(const Dune::FieldVector< ctype, dimworld > &point, const ctype *b)
Compute squared distance between point and bounding box.
Definition boundingboxtree.hh:431
bool intersectsPointBoundingBox(const Dune::FieldVector< ctype, dimworld > &point, const ctype *b)
Check whether a point is intersectin a bounding box (dimworld == 3).
Definition boundingboxtree.hh:305