version 3.11-dev
Loading...
Searching...
No Matches
intersectingentities.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//
12#ifndef DUMUX_GEOMETRY_INTERSECTING_ENTITIES_HH
13#define DUMUX_GEOMETRY_INTERSECTING_ENTITIES_HH
14
15#include <cmath>
16#include <type_traits>
17#include <vector>
18#include <algorithm>
19#include <limits>
20
21#include <dune/common/fvector.hh>
22
23#include <dumux/common/math.hh>
29
30namespace Dumux {
31
37template<int dimworld, class CoordTypeA, class CoordTypeB = CoordTypeA>
39{
40public:
41 using ctype = typename Dune::PromotionTraits<CoordTypeA, CoordTypeB>::PromotedType;
42 static constexpr int dimensionworld = dimworld;
43 using GlobalPosition = Dune::FieldVector<ctype, dimworld>;
44
45 template<class Corners>
46 explicit IntersectionInfo(std::size_t a, std::size_t b, Corners&& c)
47 : a_(a)
48 , b_(b)
49 , corners_(c.begin(), c.end())
50 {}
51
53 std::size_t first() const
54 { return a_; }
55
57 std::size_t second() const
58 { return b_; }
59
61 const std::vector<GlobalPosition>& corners() const
62 { return corners_; }
63
68 bool cornersMatch(const std::vector<GlobalPosition>& otherCorners) const
69 {
70 if (otherCorners.size() != corners_.size())
71 return false;
72
73 using std::max;
74 ctype eps2 = std::numeric_limits<ctype>::min();
75 for (int i = 1; i < corners_.size(); ++i)
76 eps2 = max(eps2, (corners_[i] - corners_[0]).two_norm2());
77
78 // We use a base epsilon of 1.5e-7 for comparisons of lengths.
79 // Since here we compare squared lengths, we multiply by its square.
80 eps2 *= 1.5e-7*1.5e-7;
81
82 for (int i = 0; i < corners_.size(); ++i)
83 // early return if none of the other corners are equal to this corner
84 if (std::none_of(otherCorners.begin(),
85 otherCorners.end(),
86 [&] (const auto& other) { return (corners_[i] - other).two_norm2() < eps2; }))
87 return false;
88
89 return true;
90 }
91
92private:
93 std::size_t a_, b_;
94 std::vector<GlobalPosition> corners_;
95};
96
101template<class EntitySet, class ctype, int dimworld>
102inline std::vector<std::size_t>
103intersectingEntities(const Dune::FieldVector<ctype, dimworld>& point,
104 const BoundingBoxTree<EntitySet>& tree,
105 bool isCartesianGrid = false)
106{
107 // Call the recursive find function to find candidates
108 std::vector<std::size_t> entities;
109 intersectingEntities(point, tree, tree.numBoundingBoxes() - 1, entities, isCartesianGrid);
110 return entities;
111}
112
117template<class EntitySet, class ctype, int dimworld>
118void intersectingEntities(const Dune::FieldVector<ctype, dimworld>& point,
119 const BoundingBoxTree<EntitySet>& tree,
120 std::size_t node,
121 std::vector<std::size_t>& entities,
122 bool isCartesianGrid = false)
123{
124 // Get the bounding box for the current node
125 const auto& bBox = tree.getBoundingBoxNode(node);
126
127 // if the point is not in the bounding box we can stop
128 if (!intersectsPointBoundingBox(point, tree.getBoundingBoxCoordinates(node))) return;
129
130 // now we know it's inside
131 // if the box is a leaf do the primitive test.
132 else if (tree.isLeaf(bBox, node))
133 {
134 const std::size_t entityIdx = bBox.child1;
135 using Geometry = typename EntitySet::Entity::Geometry;
136 // for structured cube grids or axis-aligned geometries the bounding box
137 // test is already exact, so we can skip the primitive test
138 if (isCartesianGrid || GeometryTraits<Geometry>::axisAligned)
139 entities.push_back(entityIdx);
140 else
141 {
142 const auto geometry = tree.entitySet().entity(entityIdx).geometry();
143 // if the primitive is positive it intersects the actual geometry, add the entity to the list
144 if (intersectsPointGeometry(point, geometry))
145 entities.push_back(entityIdx);
146 }
147 }
148
149 // No leaf. Check both children nodes.
150 else
151 {
152 intersectingEntities(point, tree, bBox.child0, entities, isCartesianGrid);
153 intersectingEntities(point, tree, bBox.child1, entities, isCartesianGrid);
154 }
155}
156
166template<class EntitySet, class ctype>
167void intersectingBoxes(const ctype* box,
168 const BoundingBoxTree<EntitySet>& tree,
169 std::size_t node,
170 std::vector<std::size_t>& entities)
171{
172 // if the query box doesn't overlap the node's box we can stop
173 static constexpr int dimworld = EntitySet::dimensionworld;
175 return;
176
177 // if the box is a leaf the bounding box overlap is the result
178 const auto& bBox = tree.getBoundingBoxNode(node);
179 if (tree.isLeaf(bBox, node))
180 entities.push_back(bBox.child1);
181
182 // no leaf, check both children nodes
183 else
184 {
185 intersectingBoxes(box, tree, bBox.child0, entities);
186 intersectingBoxes(box, tree, bBox.child1, entities);
187 }
188}
189
196template<class EntitySet, class ctype>
197inline std::vector<std::size_t>
198intersectingBoxes(const ctype* box, const BoundingBoxTree<EntitySet>& tree)
199{
200 std::vector<std::size_t> entities;
201 intersectingBoxes(box, tree, tree.numBoundingBoxes() - 1, entities);
202 return entities;
203}
204
212template<class EntitySet0, class EntitySet1>
214 const BoundingBoxTree<EntitySet1>& treeB,
215 std::size_t nodeA, std::size_t nodeB,
216 std::vector<std::pair<std::size_t, std::size_t>>& pairs)
217{
218 // if the two bounding boxes of the current nodes don't overlap we can stop searching
219 static constexpr int dimworld = EntitySet0::dimensionworld;
221 treeB.getBoundingBoxCoordinates(nodeB)))
222 return;
223
224 const auto& bBoxA = treeA.getBoundingBoxNode(nodeA);
225 const auto& bBoxB = treeB.getBoundingBoxNode(nodeB);
226 const bool isLeafA = treeA.isLeaf(bBoxA, nodeA);
227 const bool isLeafB = treeB.isLeaf(bBoxB, nodeB);
228
229 // both leaves: their boxes overlap, record the entity index pair
230 if (isLeafA && isLeafB)
231 pairs.emplace_back(bBoxA.child1, bBoxB.child1);
232
233 // descend into the tree that hasn't reached a leaf yet, larger tree (bigger node number) first
234 else if (isLeafA)
235 {
236 intersectingBoxes(treeA, treeB, nodeA, bBoxB.child0, pairs);
237 intersectingBoxes(treeA, treeB, nodeA, bBoxB.child1, pairs);
238 }
239 else if (isLeafB)
240 {
241 intersectingBoxes(treeA, treeB, bBoxA.child0, nodeB, pairs);
242 intersectingBoxes(treeA, treeB, bBoxA.child1, nodeB, pairs);
243 }
244 else if (nodeA > nodeB)
245 {
246 intersectingBoxes(treeA, treeB, bBoxA.child0, nodeB, pairs);
247 intersectingBoxes(treeA, treeB, bBoxA.child1, nodeB, pairs);
248 }
249 else
250 {
251 intersectingBoxes(treeA, treeB, nodeA, bBoxB.child0, pairs);
252 intersectingBoxes(treeA, treeB, nodeA, bBoxB.child1, pairs);
253 }
254}
255
261template<class EntitySet0, class EntitySet1>
262inline std::vector<std::pair<std::size_t, std::size_t>>
264{
265 static_assert(int(EntitySet0::dimensionworld) == int(EntitySet1::dimensionworld),
266 "Can only intersect bounding box trees of same world dimension");
267
268 std::vector<std::pair<std::size_t, std::size_t>> pairs;
269 intersectingBoxes(treeA, treeB, treeA.numBoundingBoxes() - 1, treeB.numBoundingBoxes() - 1, pairs);
270 return pairs;
271}
272
277template<class Geometry, class EntitySet>
278inline std::vector<IntersectionInfo<Geometry::coorddimension, typename Geometry::ctype, typename EntitySet::ctype>>
279intersectingEntities(const Geometry& geometry,
280 const BoundingBoxTree<EntitySet>& tree)
281{
283 return intersectingEntities(geometry, tree, IP{});
284}
285
290template<class Geometry, class EntitySet, class IntersectionPolicy>
291inline std::vector<IntersectionInfo<Geometry::coorddimension, typename Geometry::ctype, typename EntitySet::ctype>>
292intersectingEntities(const Geometry& geometry,
293 const BoundingBoxTree<EntitySet>& tree,
294 IntersectionPolicy intersectionPolicy)
295{
296 // check if the world dimensions match
297 static_assert(int(Geometry::coorddimension) == int(EntitySet::dimensionworld),
298 "Can only intersect geometry and bounding box tree of same world dimension");
299
300 // Create data structure for return type
301 std::vector<IntersectionInfo<Geometry::coorddimension, typename Geometry::ctype, typename EntitySet::ctype>> intersections;
303 static constexpr int dimworld = Geometry::coorddimension;
304
305 // compute the bounding box of the given geometry
306 std::array<ctype, 2*Geometry::coorddimension> bBox;
307 ctype* xMin = bBox.data(); ctype* xMax = xMin + Geometry::coorddimension;
308
309 // Get coordinates of first vertex
310 auto corner = geometry.corner(0);
311 for (std::size_t dimIdx = 0; dimIdx < dimworld; ++dimIdx)
312 xMin[dimIdx] = xMax[dimIdx] = corner[dimIdx];
313
314 // Compute the min and max over the remaining vertices
315 for (std::size_t cornerIdx = 1; cornerIdx < geometry.corners(); ++cornerIdx)
316 {
317 corner = geometry.corner(cornerIdx);
318 for (std::size_t dimIdx = 0; dimIdx < dimworld; ++dimIdx)
319 {
320 using std::max;
321 using std::min;
322 xMin[dimIdx] = min(xMin[dimIdx], corner[dimIdx]);
323 xMax[dimIdx] = max(xMax[dimIdx], corner[dimIdx]);
324 }
325 }
326
327 // Call the recursive find function to find candidates
328 intersectingEntities(geometry, tree,
329 bBox, tree.numBoundingBoxes() - 1,
330 intersections, intersectionPolicy);
331
332 return intersections;
333}
334
339template<class Geometry, class EntitySet>
340void intersectingEntities(const Geometry& geometry,
341 const BoundingBoxTree<EntitySet>& tree,
342 const std::array<typename Geometry::ctype, 2*Geometry::coorddimension>& bBox,
343 std::size_t nodeIdx,
344 std::vector<IntersectionInfo<Geometry::coorddimension,
345 typename Geometry::ctype,
346 typename EntitySet::ctype>>& intersections)
347{
349 intersectingEntities(geometry, tree, bBox, nodeIdx, intersections, IP{});
350}
351
355template<class Geometry, class EntitySet, class IntersectionPolicy>
356void intersectingEntities(const Geometry& geometry,
357 const BoundingBoxTree<EntitySet>& tree,
358 const std::array<typename Geometry::ctype, 2*Geometry::coorddimension>& bBox,
359 std::size_t nodeIdx,
360 std::vector<IntersectionInfo<Geometry::coorddimension,
361 typename Geometry::ctype,
362 typename EntitySet::ctype>>& intersections,
363 IntersectionPolicy intersectionPolicy)
364{
365 // if the two bounding boxes don't intersect we can stop searching
366 static constexpr int dimworld = Geometry::coorddimension;
368 return;
369
370 // get node info for current bounding box node
371 const auto& bBoxNode = tree.getBoundingBoxNode(nodeIdx);
372
373 // if the box is a leaf do the primitive test.
374 if (tree.isLeaf(bBoxNode, nodeIdx))
375 {
376 // eIdxA is always 0 since we intersect with exactly one geometry
377 const auto eIdxA = 0;
378 const auto eIdxB = bBoxNode.child1;
379
380 const auto geometryTree = tree.entitySet().entity(eIdxB).geometry();
381 using GeometryTree = std::decay_t<decltype(geometryTree)>;
383 using Intersection = typename IntersectionAlgorithm::Intersection;
384 Intersection intersection;
385
386 if (IntersectionAlgorithm::intersection(geometry, geometryTree, intersection))
387 {
388 static constexpr int dimIntersection = IntersectionPolicy::dimIntersection;
389 if constexpr (dimIntersection >= 2)
390 {
391 const auto triangulation = triangulate<dimIntersection, dimworld>(intersection);
392 for (unsigned int i = 0; i < triangulation.size(); ++i)
393 intersections.emplace_back(eIdxA, eIdxB, std::move(triangulation[i]));
394 }
395 else
396 intersections.emplace_back(eIdxA, eIdxB, intersection);
397 }
398 }
399
400 // No leaf. Check both children nodes.
401 else
402 {
403 intersectingEntities(geometry, tree, bBox, bBoxNode.child0, intersections);
404 intersectingEntities(geometry, tree, bBox, bBoxNode.child1, intersections);
405 }
406}
407
412template<class EntitySet0, class EntitySet1>
413inline std::vector<IntersectionInfo<EntitySet0::dimensionworld, typename EntitySet0::ctype, typename EntitySet1::ctype>>
420
425template<class EntitySet0, class EntitySet1, class IntersectionPolicy>
426inline std::vector<IntersectionInfo<EntitySet0::dimensionworld, typename EntitySet0::ctype, typename EntitySet1::ctype>>
428 const BoundingBoxTree<EntitySet1>& treeB,
429 IntersectionPolicy intersectionPolicy)
430{
431 // check if the world dimensions match
432 static_assert(int(EntitySet0::dimensionworld) == int(EntitySet1::dimensionworld),
433 "Can only intersect bounding box trees of same world dimension");
434
435 // Create data structure for return type
436 std::vector<IntersectionInfo<EntitySet0::dimensionworld, typename EntitySet0::ctype, typename EntitySet1::ctype>> intersections;
437
438 // Call the recursive find function to find candidates
439 intersectingEntities(treeA, treeB,
440 treeA.numBoundingBoxes() - 1,
441 treeB.numBoundingBoxes() - 1,
442 intersections, intersectionPolicy);
443
444 return intersections;
445}
446
451template<class EntitySet0, class EntitySet1>
453 const BoundingBoxTree<EntitySet1>& treeB,
454 std::size_t nodeA, std::size_t nodeB,
455 std::vector<IntersectionInfo<EntitySet0::dimensionworld,
456 typename EntitySet0::ctype,
457 typename EntitySet1::ctype>>& intersections)
458{
460 intersectingEntities(treeA, treeB, nodeA, nodeB, intersections, IP{});
461}
462
467template<class EntitySet0, class EntitySet1, class IntersectionPolicy>
469 const BoundingBoxTree<EntitySet1>& treeB,
470 std::size_t nodeA, std::size_t nodeB,
471 std::vector<IntersectionInfo<EntitySet0::dimensionworld,
472 typename EntitySet0::ctype,
473 typename EntitySet1::ctype>>& intersections,
474 IntersectionPolicy intersectionPolicy)
475{
476 // Get the bounding box for the current node
477 const auto& bBoxA = treeA.getBoundingBoxNode(nodeA);
478 const auto& bBoxB = treeB.getBoundingBoxNode(nodeB);
479
480 // if the two bounding boxes of the current nodes don't intersect we can stop searching
481 static constexpr int dimworld = EntitySet0::dimensionworld;
483 treeB.getBoundingBoxCoordinates(nodeB)))
484 return;
485
486 // Check if we have a leaf in treeA or treeB
487 const bool isLeafA = treeA.isLeaf(bBoxA, nodeA);
488 const bool isLeafB = treeB.isLeaf(bBoxB, nodeB);
489
490 // If both boxes are leaves do the primitive test
491 if (isLeafA && isLeafB)
492 {
493 const auto eIdxA = bBoxA.child1;
494 const auto eIdxB = bBoxB.child1;
495
496 const auto geometryA = treeA.entitySet().entity(eIdxA).geometry();
497 const auto geometryB = treeB.entitySet().entity(eIdxB).geometry();
498
499 using GeometryA = std::decay_t<decltype(geometryA)>;
500 using GeometryB = std::decay_t<decltype(geometryB)>;
502 using Intersection = typename IntersectionAlgorithm::Intersection;
503
504 if (Intersection intersection; IntersectionAlgorithm::intersection(geometryA, geometryB, intersection))
505 {
506 static constexpr int dimIntersection = IntersectionPolicy::dimIntersection;
507
508 // intersection is returned as a point cloud for dim >= 2
509 // so we have to triangulate first
510 if constexpr (dimIntersection >= 2)
511 {
512 const auto triangulation = triangulate<dimIntersection, dimworld>(intersection);
513 for (unsigned int i = 0; i < triangulation.size(); ++i)
514 intersections.emplace_back(eIdxA, eIdxB, std::move(triangulation[i]));
515 }
516 else
517 intersections.emplace_back(eIdxA, eIdxB, intersection);
518 }
519 }
520
521 // if we reached the leaf in treeA, just continue in treeB
522 else if (isLeafA)
523 {
524 intersectingEntities(treeA, treeB, nodeA, bBoxB.child0, intersections);
525 intersectingEntities(treeA, treeB, nodeA, bBoxB.child1, intersections);
526 }
527
528 // if we reached the leaf in treeB, just continue in treeA
529 else if (isLeafB)
530 {
531 intersectingEntities(treeA, treeB, bBoxA.child0, nodeB, intersections);
532 intersectingEntities(treeA, treeB, bBoxA.child1, nodeB, intersections);
533 }
534
535 // we know now that both trees didn't reach the leaf yet so
536 // we continue with the larger tree first (bigger node number)
537 else if (nodeA > nodeB)
538 {
539 intersectingEntities(treeA, treeB, bBoxA.child0, nodeB, intersections);
540 intersectingEntities(treeA, treeB, bBoxA.child1, nodeB, intersections);
541 }
542 else
543 {
544 intersectingEntities(treeA, treeB, nodeA, bBoxB.child0, intersections);
545 intersectingEntities(treeA, treeB, nodeA, bBoxB.child1, intersections);
546 }
547}
548
557template<class ctype, int dimworld>
558inline std::size_t intersectingEntityCartesianGrid(const Dune::FieldVector<ctype, dimworld>& point,
559 const Dune::FieldVector<ctype, dimworld>& min,
560 const Dune::FieldVector<ctype, dimworld>& max,
561 const std::array<int, std::size_t(dimworld)>& cells)
562{
563 std::size_t index = 0;
564 for (int i = 0; i < dimworld; ++i)
565 {
566 using std::clamp; using std::floor;
567 ctype dimOffset = clamp<ctype>(floor((point[i]-min[i])*cells[i]/(max[i]-min[i])), 0.0, cells[i]-1);
568 for (int j = 0; j < i; ++j)
569 dimOffset *= cells[j];
570 index += static_cast<std::size_t>(dimOffset);
571 }
572 return index;
573}
574
575} // end namespace Dumux
576
577#endif
An axis-aligned bounding box volume hierarchy for dune grids.
An axis-aligned bounding box volume tree implementation.
Definition boundingboxtree.hh:105
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
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
A class for geometry collision detection and intersection calculation The class can be specialized fo...
Definition geometryintersection.hh:207
An intersection object resulting from the intersection of two primitives in an entity set.
Definition intersectingentities.hh:39
static constexpr int dimensionworld
Definition intersectingentities.hh:42
bool cornersMatch(const std::vector< GlobalPosition > &otherCorners) const
Check if the corners of this intersection match with the given corners.
Definition intersectingentities.hh:68
const std::vector< GlobalPosition > & corners() const
Get the corners of the intersection geometry.
Definition intersectingentities.hh:61
IntersectionInfo(std::size_t a, std::size_t b, Corners &&c)
Definition intersectingentities.hh:46
Dune::FieldVector< ctype, dimworld > GlobalPosition
Definition intersectingentities.hh:43
std::size_t second() const
Get the index of the intersecting entity belonging to the other grid.
Definition intersectingentities.hh:57
std::size_t first() const
Get the index of the intersecting entity belonging to this grid.
Definition intersectingentities.hh:53
typename Dune::PromotionTraits< CoordTypeA, CoordTypeB >::PromotedType ctype
Definition intersectingentities.hh:41
A class for collision detection of two geometries and computation of intersection corners.
Traits telling the bounding box tree algorithms about a leaf geometry.
std::size_t intersectingEntityCartesianGrid(const Dune::FieldVector< ctype, dimworld > &point, const Dune::FieldVector< ctype, dimworld > &min, const Dune::FieldVector< ctype, dimworld > &max, const std::array< int, std::size_t(dimworld)> &cells)
Compute the index of the intersecting element of a Cartesian grid with a point The grid is given by t...
Definition intersectingentities.hh:558
Triangulation< dim, dimWorld, typename RandomAccessContainer::value_type::value_type > triangulate(const RandomAccessContainer &points)
Triangulate area given points of a convex hull (1d).
Definition triangulation.hh:81
bool intersectsPointGeometry(const Dune::FieldVector< ctype, dimworld > &point, const Geometry &g)
Find out whether a point is inside a three-dimensional geometry.
Definition intersectspointgeometry.hh:28
void intersectingBoxes(const ctype *box, const BoundingBoxTree< EntitySet > &tree, std::size_t node, std::vector< std::size_t > &entities)
Compute all entities whose bounding box overlaps the given box.
Definition intersectingentities.hh:167
std::vector< std::pair< int, std::size_t > > intersectingEntities(const Dune::FieldVector< ctype, dimworld > &point, const DistributedBoundingBoxTree< EntitySet > &tree, bool isCartesianGrid=false, bool onlyOwned=true)
Compute all intersections between entities and a point on a distributed tree.
Definition distributedintersectingentities.hh:81
Detect if a point intersects a geometry.
Define some often used mathematical functions.
Definition geometryintersection.hh:29
typename DefaultPolicyChooser< Geometry1, Geometry2 >::type DefaultPolicy
Helper alias to define the default intersection policy.
Definition geometryintersection.hh:104
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
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
static constexpr bool axisAligned
Definition geometrytraits.hh:31
Functionality to triangulate point clouds.