Line | Branch | Exec | Source |
---|---|---|---|
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-FileCopyrightInfo: Copyright © DuMux Project contributors, see AUTHORS.md in root folder | ||
5 | // SPDX-License-Identifier: GPL-3.0-or-later | ||
6 | // | ||
7 | /*! | ||
8 | * \file | ||
9 | * \ingroup Geometry | ||
10 | * \brief Helper functions for distance queries | ||
11 | */ | ||
12 | #ifndef DUMUX_GEOMETRY_DISTANCE_HH | ||
13 | #define DUMUX_GEOMETRY_DISTANCE_HH | ||
14 | |||
15 | #include <dune/common/fvector.hh> | ||
16 | #include <dune/geometry/quadraturerules.hh> | ||
17 | |||
18 | #include <dumux/common/math.hh> | ||
19 | #include <dumux/geometry/boundingboxtree.hh> | ||
20 | |||
21 | namespace Dumux { | ||
22 | |||
23 | /*! | ||
24 | * \ingroup Geometry | ||
25 | * \brief Compute the average distance from a point to a geometry by integration | ||
26 | */ | ||
27 | template<class Geometry> | ||
28 | static inline typename Geometry::ctype | ||
29 | 33058 | averageDistancePointGeometry(const typename Geometry::GlobalCoordinate& p, | |
30 | const Geometry& geometry, | ||
31 | std::size_t integrationOrder = 2) | ||
32 | { | ||
33 | 33058 | typename Geometry::ctype avgDist = 0.0; | |
34 | 63931 | const auto& quad = Dune::QuadratureRules<typename Geometry::ctype, Geometry::mydimension>::rule(geometry.type(), integrationOrder); | |
35 |
4/4✓ Branch 0 taken 48353 times.
✓ Branch 1 taken 249169 times.
✓ Branch 2 taken 48353 times.
✓ Branch 3 taken 249169 times.
|
628102 | for (const auto& qp : quad) |
36 | 1534344 | avgDist += (geometry.global(qp.position())-p).two_norm()*qp.weight()*geometry.integrationElement(qp.position()); | |
37 | 33058 | return avgDist/geometry.volume(); | |
38 | } | ||
39 | |||
40 | /*! | ||
41 | * \ingroup Geometry | ||
42 | * \brief Compute the squared distance from a point to a line through the points a and b | ||
43 | */ | ||
44 | template<class Point> | ||
45 | static inline typename Point::value_type | ||
46 | 1440 | squaredDistancePointLine(const Point& p, const Point& a, const Point& b) | |
47 | { | ||
48 | 1440 | const auto ab = b - a; | |
49 | 1440 | const auto t = (p - a)*ab/ab.two_norm2(); | |
50 | 1440 | auto proj = a; | |
51 | 1440 | proj.axpy(t, ab); | |
52 | 1440 | return (proj - p).two_norm2(); | |
53 | } | ||
54 | |||
55 | /*! | ||
56 | * \ingroup Geometry | ||
57 | * \brief Compute the squared distance from a point to a line given by a geometry with two corners | ||
58 | * \note We currently lack the a representation of a line geometry. This convenience function | ||
59 | * assumes a segment geometry (with two corners) is passed which represents a line geometry. | ||
60 | */ | ||
61 | template<class Geometry> | ||
62 | static inline typename Geometry::ctype | ||
63 | squaredDistancePointLine(const typename Geometry::GlobalCoordinate& p, const Geometry& geometry) | ||
64 | { | ||
65 | static_assert(Geometry::mydimension == 1, "Geometry has to be a line"); | ||
66 | const auto& a = geometry.corner(0); | ||
67 | const auto& b = geometry.corner(1); | ||
68 | return squaredDistancePointLine(p, a, b); | ||
69 | } | ||
70 | |||
71 | /*! | ||
72 | * \ingroup Geometry | ||
73 | * \brief Compute the distance from a point to a line through the points a and b | ||
74 | */ | ||
75 | template<class Point> | ||
76 | static inline typename Point::value_type | ||
77 | ✗ | distancePointLine(const Point& p, const Point& a, const Point& b) | |
78 |
24/48✓ Branch 3 taken 60 times.
✗ Branch 4 not taken.
✓ Branch 7 taken 60 times.
✗ Branch 8 not taken.
✓ Branch 11 taken 60 times.
✗ Branch 12 not taken.
✓ Branch 15 taken 60 times.
✗ Branch 16 not taken.
✓ Branch 19 taken 60 times.
✗ Branch 20 not taken.
✓ Branch 23 taken 60 times.
✗ Branch 24 not taken.
✓ Branch 27 taken 60 times.
✗ Branch 28 not taken.
✓ Branch 31 taken 60 times.
✗ Branch 32 not taken.
✓ Branch 35 taken 60 times.
✗ Branch 36 not taken.
✓ Branch 39 taken 60 times.
✗ Branch 40 not taken.
✓ Branch 43 taken 60 times.
✗ Branch 44 not taken.
✓ Branch 47 taken 60 times.
✗ Branch 48 not taken.
✓ Branch 51 taken 60 times.
✗ Branch 52 not taken.
✓ Branch 55 taken 60 times.
✗ Branch 56 not taken.
✓ Branch 59 taken 60 times.
✗ Branch 60 not taken.
✓ Branch 63 taken 60 times.
✗ Branch 64 not taken.
✓ Branch 67 taken 60 times.
✗ Branch 68 not taken.
✓ Branch 71 taken 60 times.
✗ Branch 72 not taken.
✓ Branch 75 taken 60 times.
✗ Branch 76 not taken.
✓ Branch 79 taken 60 times.
✗ Branch 80 not taken.
✓ Branch 83 taken 60 times.
✗ Branch 84 not taken.
✓ Branch 87 taken 60 times.
✗ Branch 88 not taken.
✓ Branch 91 taken 60 times.
✗ Branch 92 not taken.
✓ Branch 95 taken 60 times.
✗ Branch 96 not taken.
|
1440 | { using std::sqrt; return sqrt(squaredDistancePointLine(p, a, b)); } |
79 | |||
80 | /*! | ||
81 | * \ingroup Geometry | ||
82 | * \brief Compute the distance from a point to a line given by a geometry with two corners | ||
83 | * \note We currently lack the a representation of a line geometry. This convenience function | ||
84 | * assumes a segment geometry (with two corners) is passed which represents a line geometry. | ||
85 | */ | ||
86 | template<class Geometry> | ||
87 | static inline typename Geometry::ctype | ||
88 | distancePointLine(const typename Geometry::GlobalCoordinate& p, const Geometry& geometry) | ||
89 | { using std::sqrt; return sqrt(squaredDistancePointLine(p, geometry)); } | ||
90 | |||
91 | /*! | ||
92 | * \ingroup Geometry | ||
93 | * \brief Compute the squared distance from a point to the segment connecting the points a and b | ||
94 | */ | ||
95 | template<class Point> | ||
96 | static inline typename Point::value_type | ||
97 | 4798761 | squaredDistancePointSegment(const Point& p, const Point& a, const Point& b) | |
98 | { | ||
99 | 4798761 | const auto ab = b - a; | |
100 | 4798761 | const auto ap = p - a; | |
101 | 4798761 | const auto t = ap*ab; | |
102 | |||
103 |
2/2✓ Branch 0 taken 1679250 times.
✓ Branch 1 taken 721673 times.
|
4798761 | if (t <= 0.0) |
104 | return ap.two_norm2(); | ||
105 | |||
106 | 3355415 | const auto lengthSq = ab.two_norm2(); | |
107 |
2/2✓ Branch 0 taken 854634 times.
✓ Branch 1 taken 824616 times.
|
3355415 | if (t >= lengthSq) |
108 | 3418536 | return (b - p).two_norm2(); | |
109 | |||
110 | 1646147 | auto proj = a; | |
111 | 1646147 | proj.axpy(t/lengthSq, ab); | |
112 | 3292294 | return (proj - p).two_norm2(); | |
113 | } | ||
114 | |||
115 | /*! | ||
116 | * \ingroup Geometry | ||
117 | * \brief Compute the squared distance from a point to a given segment geometry | ||
118 | */ | ||
119 | template<class Geometry> | ||
120 | static inline typename Geometry::ctype | ||
121 | 4114 | squaredDistancePointSegment(const typename Geometry::GlobalCoordinate& p, const Geometry& geometry) | |
122 | { | ||
123 | static_assert(Geometry::mydimension == 1, "Geometry has to be a segment"); | ||
124 | 17938 | const auto& a = geometry.corner(0); | |
125 | 11026 | const auto& b = geometry.corner(1); | |
126 | 11026 | return squaredDistancePointSegment(p, a, b); | |
127 | } | ||
128 | |||
129 | /*! | ||
130 | * \ingroup Geometry | ||
131 | * \brief Compute the distance from a point to the segment connecting the points a and b | ||
132 | */ | ||
133 | template<class Point> | ||
134 | static inline typename Point::value_type | ||
135 | distancePointSegment(const Point& p, const Point& a, const Point& b) | ||
136 | 6080 | { using std::sqrt; return sqrt(squaredDistancePointSegment(p, a, b)); } | |
137 | |||
138 | /*! | ||
139 | * \ingroup Geometry | ||
140 | * \brief Compute the distance from a point to a given segment geometry | ||
141 | */ | ||
142 | template<class Geometry> | ||
143 | static inline typename Geometry::ctype | ||
144 | distancePointSegment(const typename Geometry::GlobalCoordinate& p, const Geometry& geometry) | ||
145 | 28 | { using std::sqrt; return sqrt(squaredDistancePointSegment(p, geometry)); } | |
146 | |||
147 | /*! | ||
148 | * \ingroup Geometry | ||
149 | * \brief Compute the shortest squared distance from a point to the triangle connecting the points a, b and c | ||
150 | * See https://www.iquilezles.org/www/articles/triangledistance/triangledistance.htm. | ||
151 | */ | ||
152 | template<class Point> | ||
153 | static inline typename Point::value_type | ||
154 | 845393 | squaredDistancePointTriangle(const Point& p, const Point& a, const Point& b, const Point& c) | |
155 | { | ||
156 | static_assert(Point::dimension == 3, "Only works in 3D"); | ||
157 | 845393 | const auto ab = b - a; | |
158 | 845393 | const auto bc = c - b; | |
159 | 845393 | const auto ca = a - c; | |
160 | 845393 | const auto normal = crossProduct(ab, ca); | |
161 | |||
162 | 845393 | const auto ap = p - a; | |
163 | 845393 | const auto bp = p - b; | |
164 | 845393 | const auto cp = p - c; | |
165 | |||
166 | 1690786 | const auto sum = sign(crossProduct(ab, normal)*ap) | |
167 | 1690786 | + sign(crossProduct(bc, normal)*bp) | |
168 |
2/2✓ Branch 1 taken 46435 times.
✓ Branch 2 taken 798958 times.
|
1690786 | + sign(crossProduct(ca, normal)*cp); |
169 | |||
170 | // if there is no orthogonal projection | ||
171 | // (point is outside the infinite prism implied by the triangle and its surface normal) | ||
172 | // compute distance to the edges (codim-1 facets) | ||
173 |
2/2✓ Branch 0 taken 46435 times.
✓ Branch 1 taken 798958 times.
|
845393 | if (sum < 2.0) |
174 | { | ||
175 | using std::min; | ||
176 | 2396874 | return min({squaredDistancePointSegment(p, a, b), | |
177 | 798958 | squaredDistancePointSegment(p, a, c), | |
178 | 798958 | squaredDistancePointSegment(p, b, c)}); | |
179 | } | ||
180 | // compute distance via orthogonal projection | ||
181 | else | ||
182 | { | ||
183 | 46435 | const auto tmp = normal*ap; | |
184 | 92870 | return tmp*tmp / (normal*normal); | |
185 | } | ||
186 | } | ||
187 | |||
188 | /*! | ||
189 | * \ingroup Geometry | ||
190 | * \brief Compute the shortest squared distance from a point to a given triangle geometry | ||
191 | */ | ||
192 | template<class Geometry> | ||
193 | static inline typename Geometry::ctype | ||
194 | 428134 | squaredDistancePointTriangle(const typename Geometry::GlobalCoordinate& p, const Geometry& geometry) | |
195 | { | ||
196 | static_assert(Geometry::coorddimension == 3, "Only works in 3D"); | ||
197 | static_assert(Geometry::mydimension == 2, "Geometry has to be a triangle"); | ||
198 |
2/4✗ Branch 0 not taken.
✓ Branch 1 taken 214067 times.
✗ Branch 2 not taken.
✓ Branch 3 taken 214067 times.
|
856268 | assert(geometry.corners() == 3); |
199 | 428134 | const auto& a = geometry.corner(0); | |
200 | 428134 | const auto& b = geometry.corner(1); | |
201 | 428134 | const auto& c = geometry.corner(2); | |
202 | 428134 | return squaredDistancePointTriangle(p, a, b, c); | |
203 | } | ||
204 | |||
205 | /*! | ||
206 | * \ingroup Geometry | ||
207 | * \brief Compute the shortest distance from a point to the triangle connecting the points a, b and c | ||
208 | */ | ||
209 | template<class Point> | ||
210 | static inline typename Point::value_type | ||
211 | distancePointTriangle(const Point& p, const Point& a, const Point& b, const Point& c) | ||
212 |
8/16✓ Branch 2 taken 60 times.
✗ Branch 3 not taken.
✓ Branch 6 taken 60 times.
✗ Branch 7 not taken.
✓ Branch 10 taken 60 times.
✗ Branch 11 not taken.
✓ Branch 14 taken 60 times.
✗ Branch 15 not taken.
✓ Branch 18 taken 60 times.
✗ Branch 19 not taken.
✓ Branch 22 taken 60 times.
✗ Branch 23 not taken.
✓ Branch 26 taken 60 times.
✗ Branch 27 not taken.
✓ Branch 30 taken 60 times.
✗ Branch 31 not taken.
|
480 | { using std::sqrt; return sqrt(squaredDistancePointTriangle(p, a, b, c)); } |
213 | |||
214 | /*! | ||
215 | * \ingroup Geometry | ||
216 | * \brief Compute the shortest distance from a point to a given triangle geometry | ||
217 | */ | ||
218 | template<class Geometry> | ||
219 | static inline typename Geometry::ctype | ||
220 | distancePointTriangle(const typename Geometry::GlobalCoordinate& p, const Geometry& geometry) | ||
221 |
4/8✓ Branch 2 taken 60 times.
✗ Branch 3 not taken.
✓ Branch 6 taken 60 times.
✗ Branch 7 not taken.
✓ Branch 10 taken 60 times.
✗ Branch 11 not taken.
✓ Branch 14 taken 60 times.
✗ Branch 15 not taken.
|
240 | { using std::sqrt; return sqrt(squaredDistancePointTriangle(p, geometry)); } |
222 | |||
223 | /*! | ||
224 | * \ingroup Geometry | ||
225 | * \brief Compute the shortest squared distance from a point to a given polygon geometry | ||
226 | * \note We only support triangles and quadrilaterals so far. | ||
227 | */ | ||
228 | template<class Geometry> | ||
229 | static inline typename Geometry::ctype | ||
230 | 1058485 | squaredDistancePointPolygon(const typename Geometry::GlobalCoordinate& p, const Geometry& geometry) | |
231 | { | ||
232 |
4/4✓ Branch 0 taken 213827 times.
✓ Branch 1 taken 315408 times.
✓ Branch 2 taken 213827 times.
✓ Branch 3 taken 315408 times.
|
2116955 | if (geometry.corners() == 3) |
233 | 427654 | return squaredDistancePointTriangle(p, geometry); | |
234 |
2/4✓ Branch 0 taken 315408 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 315408 times.
✗ Branch 3 not taken.
|
1261647 | else if (geometry.corners() == 4) |
235 | { | ||
236 | 630831 | const auto& a = geometry.corner(0); | |
237 | 630831 | const auto& b = geometry.corner(1); | |
238 | 630831 | const auto& c = geometry.corner(2); | |
239 | 630831 | const auto& d = geometry.corner(3); | |
240 | |||
241 | using std::min; | ||
242 |
2/2✓ Branch 0 taken 115577 times.
✓ Branch 1 taken 199846 times.
|
630831 | return min(squaredDistancePointTriangle(p, a, b, d), |
243 | 1261647 | squaredDistancePointTriangle(p, a, d, c)); | |
244 | } | ||
245 | else | ||
246 | ✗ | DUNE_THROW(Dune::NotImplemented, "Polygon with " << geometry.corners() << " corners not supported"); | |
247 | } | ||
248 | |||
249 | /*! | ||
250 | * \ingroup Geometry | ||
251 | * \brief Compute the shortest distance from a point to a given polygon geometry | ||
252 | * \note We only support triangles and quadrilaterals so far. | ||
253 | */ | ||
254 | template<class Geometry> | ||
255 | static inline typename Geometry::ctype | ||
256 | distancePointPolygon(const typename Geometry::GlobalCoordinate& p, const Geometry& geometry) | ||
257 | 15 | { using std::sqrt; return sqrt(squaredDistancePointPolygon(p, geometry)); } | |
258 | |||
259 | /*! | ||
260 | * \ingroup Geometry | ||
261 | * \brief Compute the average distance from a segment to a geometry by integration | ||
262 | */ | ||
263 | template<class Geometry> | ||
264 | static inline typename Geometry::ctype | ||
265 | 380 | averageDistanceSegmentGeometry(const typename Geometry::GlobalCoordinate& a, | |
266 | const typename Geometry::GlobalCoordinate& b, | ||
267 | const Geometry& geometry, | ||
268 | std::size_t integrationOrder = 2) | ||
269 | { | ||
270 | 380 | typename Geometry::ctype avgDist = 0.0; | |
271 | 760 | const auto& quad = Dune::QuadratureRules<typename Geometry::ctype, Geometry::mydimension>::rule(geometry.type(), integrationOrder); | |
272 |
4/4✓ Branch 0 taken 380 times.
✓ Branch 1 taken 3040 times.
✓ Branch 2 taken 380 times.
✓ Branch 3 taken 3040 times.
|
7220 | for (const auto& qp : quad) |
273 | 12160 | avgDist += distancePointSegment(geometry.global(qp.position()), a, b)*qp.weight()*geometry.integrationElement(qp.position()); | |
274 | 380 | return avgDist/geometry.volume(); | |
275 | } | ||
276 | |||
277 | /*! | ||
278 | * \ingroup Geometry | ||
279 | * \brief Compute the shortest distance between two points | ||
280 | */ | ||
281 | template<class ctype, int dimWorld> | ||
282 | static inline ctype distance(const Dune::FieldVector<ctype, dimWorld>& a, | ||
283 | const Dune::FieldVector<ctype, dimWorld>& b) | ||
284 | { return (a-b).two_norm(); } | ||
285 | |||
286 | /*! | ||
287 | * \ingroup Geometry | ||
288 | * \brief Compute the shortest squared distance between two points | ||
289 | */ | ||
290 | template<class ctype, int dimWorld> | ||
291 | 480 | static inline ctype squaredDistance(const Dune::FieldVector<ctype, dimWorld>& a, | |
292 | const Dune::FieldVector<ctype, dimWorld>& b) | ||
293 | 480 | { return (a-b).two_norm2(); } | |
294 | |||
295 | |||
296 | namespace Detail { | ||
297 | |||
298 | // helper struct to compute distance between two geometries, specialized below | ||
299 | template<class Geo1, class Geo2, | ||
300 | int dimWorld = Geo1::coorddimension, | ||
301 | int dim1 = Geo1::mydimension, int dim2 = Geo2::mydimension> | ||
302 | struct GeometrySquaredDistance | ||
303 | { | ||
304 | static_assert(Geo1::coorddimension == Geo2::coorddimension, "Geometries have to have the same coordinate dimensions"); | ||
305 | static auto distance(const Geo1& geo1, const Geo2& geo2) | ||
306 | { | ||
307 | DUNE_THROW(Dune::NotImplemented, "Geometry distance computation not implemented for dimworld = " | ||
308 | << dimWorld << ", dim1 = " << dim1 << ", dim2 = " << dim2); | ||
309 | } | ||
310 | }; | ||
311 | |||
312 | // distance point-point | ||
313 | template<class Geo1, class Geo2, int dimWorld> | ||
314 | struct GeometrySquaredDistance<Geo1, Geo2, dimWorld, 0, 0> | ||
315 | { | ||
316 | static_assert(Geo1::coorddimension == Geo2::coorddimension, "Geometries have to have the same coordinate dimensions"); | ||
317 | 720 | static auto distance(const Geo1& geo1, const Geo2& geo2) | |
318 | 1440 | { return Dumux::squaredDistance(geo1.corner(0), geo2.corner(0)); } | |
319 | }; | ||
320 | |||
321 | // distance segment-point | ||
322 | template<class Geo1, class Geo2, int dimWorld> | ||
323 | struct GeometrySquaredDistance<Geo1, Geo2, dimWorld, 1, 0> | ||
324 | { | ||
325 | static_assert(Geo1::coorddimension == Geo2::coorddimension, "Geometries have to have the same coordinate dimensions"); | ||
326 | 720 | static auto distance(const Geo1& geo1, const Geo2& geo2) | |
327 | 1800 | { return squaredDistancePointSegment(geo2.corner(0), geo1); } | |
328 | }; | ||
329 | |||
330 | // distance point-segment | ||
331 | template<class Geo1, class Geo2, int dimWorld> | ||
332 | struct GeometrySquaredDistance<Geo1, Geo2, dimWorld, 0, 1> | ||
333 | { | ||
334 | static_assert(Geo1::coorddimension == Geo2::coorddimension, "Geometries have to have the same coordinate dimensions"); | ||
335 | static auto distance(const Geo1& geo1, const Geo2& geo2) | ||
336 | { return squaredDistancePointSegment(geo1.corner(0), geo2); } | ||
337 | }; | ||
338 | |||
339 | // distance point-polygon | ||
340 | template<class Geo1, class Geo2, int dimWorld> | ||
341 | struct GeometrySquaredDistance<Geo1, Geo2, dimWorld, 0, 2> | ||
342 | { | ||
343 | static_assert(Geo1::coorddimension == Geo2::coorddimension, "Geometries have to have the same coordinate dimensions"); | ||
344 | 480 | static inline auto distance(const Geo1& geo1, const Geo2& geo2) | |
345 | 720 | { return squaredDistancePointPolygon(geo1.corner(0), geo2); } | |
346 | }; | ||
347 | |||
348 | // distance polygon-point | ||
349 | template<class Geo1, class Geo2, int dimWorld> | ||
350 | struct GeometrySquaredDistance<Geo1, Geo2, dimWorld, 2, 0> | ||
351 | { | ||
352 | static_assert(Geo1::coorddimension == Geo2::coorddimension, "Geometries have to have the same coordinate dimensions"); | ||
353 | 480 | static inline auto distance(const Geo1& geo1, const Geo2& geo2) | |
354 | 720 | { return squaredDistancePointPolygon(geo2.corner(0), geo1); } | |
355 | }; | ||
356 | |||
357 | } // end namespace Detail | ||
358 | |||
359 | /*! | ||
360 | * \ingroup Geometry | ||
361 | * \brief Compute the shortest distance between two geometries | ||
362 | */ | ||
363 | template<class Geo1, class Geo2> | ||
364 | static inline auto squaredDistance(const Geo1& geo1, const Geo2& geo2) | ||
365 | 4560 | { return Detail::GeometrySquaredDistance<Geo1, Geo2>::distance(geo1, geo2); } | |
366 | |||
367 | /*! | ||
368 | * \ingroup Geometry | ||
369 | * \brief Compute the shortest distance between two geometries | ||
370 | */ | ||
371 | template<class Geo1, class Geo2> | ||
372 | 3360 | static inline auto distance(const Geo1& geo1, const Geo2& geo2) | |
373 |
28/56✓ Branch 2 taken 60 times.
✗ Branch 3 not taken.
✓ Branch 6 taken 60 times.
✗ Branch 7 not taken.
✓ Branch 10 taken 60 times.
✗ Branch 11 not taken.
✓ Branch 14 taken 60 times.
✗ Branch 15 not taken.
✓ Branch 17 taken 60 times.
✗ Branch 18 not taken.
✓ Branch 20 taken 60 times.
✗ Branch 21 not taken.
✓ Branch 23 taken 60 times.
✗ Branch 24 not taken.
✓ Branch 26 taken 60 times.
✗ Branch 27 not taken.
✓ Branch 29 taken 60 times.
✗ Branch 30 not taken.
✓ Branch 32 taken 60 times.
✗ Branch 33 not taken.
✓ Branch 35 taken 60 times.
✗ Branch 36 not taken.
✓ Branch 38 taken 60 times.
✗ Branch 39 not taken.
✓ Branch 42 taken 60 times.
✗ Branch 43 not taken.
✓ Branch 46 taken 60 times.
✗ Branch 47 not taken.
✓ Branch 50 taken 60 times.
✗ Branch 51 not taken.
✓ Branch 54 taken 60 times.
✗ Branch 55 not taken.
✓ Branch 58 taken 60 times.
✗ Branch 59 not taken.
✓ Branch 62 taken 60 times.
✗ Branch 63 not taken.
✓ Branch 65 taken 60 times.
✗ Branch 66 not taken.
✓ Branch 68 taken 60 times.
✗ Branch 69 not taken.
✓ Branch 71 taken 60 times.
✗ Branch 72 not taken.
✓ Branch 74 taken 60 times.
✗ Branch 75 not taken.
✓ Branch 77 taken 60 times.
✗ Branch 78 not taken.
✓ Branch 80 taken 60 times.
✗ Branch 81 not taken.
✓ Branch 83 taken 60 times.
✗ Branch 84 not taken.
✓ Branch 86 taken 60 times.
✗ Branch 87 not taken.
✓ Branch 90 taken 60 times.
✗ Branch 91 not taken.
✓ Branch 94 taken 60 times.
✗ Branch 95 not taken.
|
4560 | { using std::sqrt; return sqrt(squaredDistance(geo1, geo2)); } |
374 | |||
375 | |||
376 | //! Distance implementation details | ||
377 | namespace Detail { | ||
378 | |||
379 | /*! | ||
380 | * \ingroup Geometry | ||
381 | * \brief Compute the closest entity in an AABB tree (index and shortest squared distance) recursively | ||
382 | * \note specialization for geometries with dimension larger than points | ||
383 | */ | ||
384 | template<class EntitySet, class ctype, int dimworld, | ||
385 | typename std::enable_if_t<(EntitySet::Entity::Geometry::mydimension > 0), int> = 0> | ||
386 | 7215428 | void closestEntity(const Dune::FieldVector<ctype, dimworld>& point, | |
387 | const BoundingBoxTree<EntitySet>& tree, | ||
388 | std::size_t node, | ||
389 | ctype& minSquaredDistance, | ||
390 | std::size_t& eIdx) | ||
391 | { | ||
392 | // Get the bounding box for the current node | ||
393 |
2/2✓ Branch 0 taken 2337735 times.
✓ Branch 1 taken 1300243 times.
|
7215428 | const auto& bBox = tree.getBoundingBoxNode(node); |
394 | |||
395 | // If bounding box is outside radius, then don't search further | ||
396 |
2/2✓ Branch 0 taken 2337735 times.
✓ Branch 1 taken 1300243 times.
|
7215428 | const auto squaredDistance = squaredDistancePointBoundingBox( |
397 | point, tree.getBoundingBoxCoordinates(node) | ||
398 | ); | ||
399 | |||
400 | // do not continue if the AABB is further away than the current minimum | ||
401 |
2/2✓ Branch 0 taken 2337735 times.
✓ Branch 1 taken 1300243 times.
|
7215428 | if (squaredDistance > minSquaredDistance) return; |
402 | |||
403 | // If the bounding box is a leaf, update distance and index with primitive test | ||
404 |
2/2✓ Branch 0 taken 535790 times.
✓ Branch 1 taken 1801945 times.
|
4642038 | else if (tree.isLeaf(bBox, node)) |
405 | { | ||
406 | 1065244 | const std::size_t entityIdx = bBox.child1; | |
407 | 535790 | const auto squaredDistance = [&]{ | |
408 | 535790 | const auto geometry = tree.entitySet().entity(entityIdx).geometry(); | |
409 | if constexpr (EntitySet::Entity::Geometry::mydimension == 2) | ||
410 | 528597 | return squaredDistancePointPolygon(point, geometry); | |
411 | else if constexpr (EntitySet::Entity::Geometry::mydimension == 1) | ||
412 | 7515 | return squaredDistancePointSegment(point, geometry); | |
413 | else | ||
414 | DUNE_THROW(Dune::NotImplemented, "squaredDistance to entity with dim>2"); | ||
415 | 1601034 | }(); | |
416 | |||
417 |
2/2✓ Branch 0 taken 49432 times.
✓ Branch 1 taken 486358 times.
|
1065244 | if (squaredDistance < minSquaredDistance) |
418 | { | ||
419 | 92528 | eIdx = entityIdx; | |
420 | 92528 | minSquaredDistance = squaredDistance; | |
421 | } | ||
422 | } | ||
423 | |||
424 | // Check the children nodes recursively | ||
425 | else | ||
426 | { | ||
427 | 3576794 | closestEntity(point, tree, bBox.child0, minSquaredDistance, eIdx); | |
428 | 3576794 | closestEntity(point, tree, bBox.child1, minSquaredDistance, eIdx); | |
429 | } | ||
430 | } | ||
431 | |||
432 | /*! | ||
433 | * \ingroup Geometry | ||
434 | * \brief Compute the closest entity in an AABB tree (index and shortest squared distance) recursively | ||
435 | * \note specialization for point geometries (point cloud AABB tree) | ||
436 | */ | ||
437 | template<class EntitySet, class ctype, int dimworld, | ||
438 | typename std::enable_if_t<(EntitySet::Entity::Geometry::mydimension == 0), int> = 0> | ||
439 | 10517322 | void closestEntity(const Dune::FieldVector<ctype, dimworld>& point, | |
440 | const BoundingBoxTree<EntitySet>& tree, | ||
441 | std::size_t node, | ||
442 | ctype& minSquaredDistance, | ||
443 | std::size_t& eIdx) | ||
444 | { | ||
445 | // Get the bounding box for the current node | ||
446 |
2/2✓ Branch 0 taken 3105778 times.
✓ Branch 1 taken 7459956 times.
|
20972804 | const auto& bBox = tree.getBoundingBoxNode(node); |
447 | |||
448 | // If the bounding box is a leaf, update distance and index with primitive test | ||
449 |
2/2✓ Branch 0 taken 3105778 times.
✓ Branch 1 taken 7459956 times.
|
20972804 | if (tree.isLeaf(bBox, node)) |
450 | { | ||
451 | 6138906 | const std::size_t entityIdx = bBox.child1; | |
452 | 12277812 | const auto& p = tree.entitySet().entity(entityIdx).geometry().corner(0); | |
453 | 6220856 | const auto squaredDistance = (p-point).two_norm2(); | |
454 | |||
455 |
2/2✓ Branch 0 taken 1408555 times.
✓ Branch 1 taken 1697223 times.
|
6138906 | if (squaredDistance < minSquaredDistance) |
456 | { | ||
457 | 2760040 | eIdx = entityIdx; | |
458 | 2760040 | minSquaredDistance = squaredDistance; | |
459 | } | ||
460 | } | ||
461 | |||
462 | // Check the children nodes recursively | ||
463 | else | ||
464 | { | ||
465 | // If bounding box is outside radius, then don't search further | ||
466 |
2/2✓ Branch 0 taken 5265823 times.
✓ Branch 1 taken 2194133 times.
|
14833898 | const auto squaredDistance = squaredDistancePointBoundingBox( |
467 | point, tree.getBoundingBoxCoordinates(node) | ||
468 | ); | ||
469 | |||
470 | // do not continue if the AABB is further away than the current minimum | ||
471 |
2/2✓ Branch 0 taken 5265823 times.
✓ Branch 1 taken 2194133 times.
|
14833898 | if (squaredDistance > minSquaredDistance) return; |
472 | |||
473 | 10455482 | closestEntity(point, tree, bBox.child0, minSquaredDistance, eIdx); | |
474 | 10455482 | closestEntity(point, tree, bBox.child1, minSquaredDistance, eIdx); | |
475 | } | ||
476 | } | ||
477 | |||
478 | } // end namespace Detail | ||
479 | |||
480 | /*! | ||
481 | * \ingroup Geometry | ||
482 | * \brief Compute the closest entity in an AABB tree to a point (index and shortest squared distance) | ||
483 | * \param point the point | ||
484 | * \param tree the AABB tree | ||
485 | * \param minSquaredDistance conservative estimate of the minimum distance | ||
486 | * | ||
487 | * \note it is important that if an estimate is provided for minSquaredDistance to choose | ||
488 | * this estimate to be larger than the expected result. If the minSquaredDistance is smaller | ||
489 | * or equal to the result the returned entity index will be zero and the distance is equal | ||
490 | * to the estimate. However, this can also be the correct result. When in doubt, use the | ||
491 | * default parameter value. | ||
492 | */ | ||
493 | template<class EntitySet, class ctype, int dimworld> | ||
494 | 136352 | std::pair<ctype, std::size_t> closestEntity(const Dune::FieldVector<ctype, dimworld>& point, | |
495 | const BoundingBoxTree<EntitySet>& tree, | ||
496 | ctype minSquaredDistance = std::numeric_limits<ctype>::max()) | ||
497 | { | ||
498 | 136352 | std::size_t eIdx = 0; | |
499 | 272704 | Detail::closestEntity(point, tree, tree.numBoundingBoxes() - 1, minSquaredDistance, eIdx); | |
500 | using std::sqrt; | ||
501 | 272704 | return { minSquaredDistance, eIdx }; | |
502 | } | ||
503 | |||
504 | /*! | ||
505 | * \ingroup Geometry | ||
506 | * \brief Compute the shortest squared distance to entities in an AABB tree | ||
507 | */ | ||
508 | template<class EntitySet, class ctype, int dimworld> | ||
509 | ctype squaredDistance(const Dune::FieldVector<ctype, dimworld>& point, | ||
510 | const BoundingBoxTree<EntitySet>& tree, | ||
511 | ctype minSquaredDistance = std::numeric_limits<ctype>::max()) | ||
512 | { | ||
513 | 34088 | return closestEntity(point, tree, minSquaredDistance).first; | |
514 | } | ||
515 | |||
516 | /*! | ||
517 | * \ingroup Geometry | ||
518 | * \brief Compute the shortest distance to entities in an AABB tree | ||
519 | */ | ||
520 | template<class EntitySet, class ctype, int dimworld> | ||
521 | ctype distance(const Dune::FieldVector<ctype, dimworld>& point, | ||
522 | const BoundingBoxTree<EntitySet>& tree, | ||
523 | ctype minSquaredDistance = std::numeric_limits<ctype>::max()) | ||
524 | { | ||
525 | using std::sqrt; | ||
526 | return sqrt(squaredDistance(point, tree, minSquaredDistance)); | ||
527 | } | ||
528 | |||
529 | } // end namespace Dumux | ||
530 | |||
531 | #endif | ||
532 |