3.5-git
DUNE for Multi-{Phase, Component, Scale, Physics, ...} flow and transport in porous media
distance.hh
Go to the documentation of this file.
1/*****************************************************************************
2 * See the file COPYING for full copying permissions. *
3 * *
4 * This program is free software: you can redistribute it and/or modify *
5 * it under the terms of the GNU General Public License as published by *
6 * the Free Software Foundation, either version 3 of the License, or *
7 * (at your option) any later version. *
8 * *
9 * This program 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 *
12 * GNU General Public License for more details. *
13 * *
14 * You should have received a copy of the GNU General Public License *
15 * along with this program. If not, see <http://www.gnu.org/licenses/>. *
16 *****************************************************************************/
22#ifndef DUMUX_GEOMETRY_DISTANCE_HH
23#define DUMUX_GEOMETRY_DISTANCE_HH
24
25#include <dune/common/fvector.hh>
26#include <dune/geometry/quadraturerules.hh>
27
28#include <dumux/common/math.hh>
30
31namespace Dumux {
32
37template<class Geometry>
38static inline typename Geometry::ctype
39averageDistancePointGeometry(const typename Geometry::GlobalCoordinate& p,
40 const Geometry& geometry,
41 std::size_t integrationOrder = 2)
42{
43 typename Geometry::ctype avgDist = 0.0;
44 const auto& quad = Dune::QuadratureRules<typename Geometry::ctype, Geometry::mydimension>::rule(geometry.type(), integrationOrder);
45 for (const auto& qp : quad)
46 avgDist += (geometry.global(qp.position())-p).two_norm()*qp.weight()*geometry.integrationElement(qp.position());
47 return avgDist/geometry.volume();
48}
49
54template<class Point>
55static inline typename Point::value_type
56squaredDistancePointLine(const Point& p, const Point& a, const Point& b)
57{
58 const auto ab = b - a;
59 const auto t = (p - a)*ab/ab.two_norm2();
60 auto proj = a;
61 proj.axpy(t, ab);
62 return (proj - p).two_norm2();
63}
64
71template<class Geometry>
72static inline typename Geometry::ctype
73squaredDistancePointLine(const typename Geometry::GlobalCoordinate& p, const Geometry& geometry)
74{
75 static_assert(Geometry::mydimension == 1, "Geometry has to be a line");
76 const auto& a = geometry.corner(0);
77 const auto& b = geometry.corner(1);
78 return squaredDistancePointLine(p, a, b);
79}
80
85template<class Point>
86static inline typename Point::value_type
87distancePointLine(const Point& p, const Point& a, const Point& b)
88{ using std::sqrt; return sqrt(squaredDistancePointLine(p, a, b)); }
89
96template<class Geometry>
97static inline typename Geometry::ctype
98distancePointLine(const typename Geometry::GlobalCoordinate& p, const Geometry& geometry)
99{ using std::sqrt; return sqrt(squaredDistancePointLine(p, geometry)); }
100
105template<class Point>
106static inline typename Point::value_type
107squaredDistancePointSegment(const Point& p, const Point& a, const Point& b)
108{
109 const auto ab = b - a;
110 const auto ap = p - a;
111 const auto t = ap*ab;
112
113 if (t <= 0.0)
114 return ap.two_norm2();
115
116 const auto lengthSq = ab.two_norm2();
117 if (t >= lengthSq)
118 return (b - p).two_norm2();
119
120 auto proj = a;
121 proj.axpy(t/lengthSq, ab);
122 return (proj - p).two_norm2();
123}
124
129template<class Geometry>
130static inline typename Geometry::ctype
131squaredDistancePointSegment(const typename Geometry::GlobalCoordinate& p, const Geometry& geometry)
132{
133 static_assert(Geometry::mydimension == 1, "Geometry has to be a segment");
134 const auto& a = geometry.corner(0);
135 const auto& b = geometry.corner(1);
136 return squaredDistancePointSegment(p, a, b);
137}
138
143template<class Point>
144static inline typename Point::value_type
145distancePointSegment(const Point& p, const Point& a, const Point& b)
146{ using std::sqrt; return sqrt(squaredDistancePointSegment(p, a, b)); }
147
152template<class Geometry>
153static inline typename Geometry::ctype
154distancePointSegment(const typename Geometry::GlobalCoordinate& p, const Geometry& geometry)
155{ using std::sqrt; return sqrt(squaredDistancePointSegment(p, geometry)); }
156
162template<class Point>
163static inline typename Point::value_type
164squaredDistancePointTriangle(const Point& p, const Point& a, const Point& b, const Point& c)
165{
166 static_assert(Point::dimension == 3, "Only works in 3D");
167 const auto ab = b - a;
168 const auto bc = c - b;
169 const auto ca = a - c;
170 const auto normal = crossProduct(ab, ca);
171
172 const auto ap = p - a;
173 const auto bp = p - b;
174 const auto cp = p - c;
175
176 const auto sum = sign(crossProduct(ab, normal)*ap)
177 + sign(crossProduct(bc, normal)*bp)
178 + sign(crossProduct(ca, normal)*cp);
179
180 // if there is no orthogonal projection
181 // (point is outside the infinite prism implied by the triangle and its surface normal)
182 // compute distance to the edges (codim-1 facets)
183 if (sum < 2.0)
184 {
185 using std::min;
186 return min({squaredDistancePointSegment(p, a, b),
189 }
190 // compute distance via orthogonal projection
191 else
192 {
193 const auto tmp = normal*ap;
194 return tmp*tmp / (normal*normal);
195 }
196}
197
202template<class Geometry>
203static inline typename Geometry::ctype
204squaredDistancePointTriangle(const typename Geometry::GlobalCoordinate& p, const Geometry& geometry)
205{
206 static_assert(Geometry::coorddimension == 3, "Only works in 3D");
207 static_assert(Geometry::mydimension == 2, "Geometry has to be a triangle");
208 assert(geometry.corners() == 3);
209 const auto& a = geometry.corner(0);
210 const auto& b = geometry.corner(1);
211 const auto& c = geometry.corner(2);
212 return squaredDistancePointTriangle(p, a, b, c);
213}
214
219template<class Point>
220static inline typename Point::value_type
221distancePointTriangle(const Point& p, const Point& a, const Point& b, const Point& c)
222{ using std::sqrt; return sqrt(squaredDistancePointTriangle(p, a, b, c)); }
223
228template<class Geometry>
229static inline typename Geometry::ctype
230distancePointTriangle(const typename Geometry::GlobalCoordinate& p, const Geometry& geometry)
231{ using std::sqrt; return sqrt(squaredDistancePointTriangle(p, geometry)); }
232
238template<class Geometry>
239static inline typename Geometry::ctype
240squaredDistancePointPolygon(const typename Geometry::GlobalCoordinate& p, const Geometry& geometry)
241{
242 if (geometry.corners() == 3)
243 return squaredDistancePointTriangle(p, geometry);
244 else if (geometry.corners() == 4)
245 {
246 const auto& a = geometry.corner(0);
247 const auto& b = geometry.corner(1);
248 const auto& c = geometry.corner(2);
249 const auto& d = geometry.corner(3);
250
251 using std::min;
252 return min(squaredDistancePointTriangle(p, a, b, d),
253 squaredDistancePointTriangle(p, a, d, c));
254 }
255 else
256 DUNE_THROW(Dune::NotImplemented, "Polygon with " << geometry.corners() << " corners not supported");
257}
258
264template<class Geometry>
265static inline typename Geometry::ctype
266distancePointPolygon(const typename Geometry::GlobalCoordinate& p, const Geometry& geometry)
267{ using std::sqrt; return sqrt(squaredDistancePointPolygon(p, geometry)); }
268
273template<class Geometry>
274static inline typename Geometry::ctype
275averageDistanceSegmentGeometry(const typename Geometry::GlobalCoordinate& a,
276 const typename Geometry::GlobalCoordinate& b,
277 const Geometry& geometry,
278 std::size_t integrationOrder = 2)
279{
280 typename Geometry::ctype avgDist = 0.0;
281 const auto& quad = Dune::QuadratureRules<typename Geometry::ctype, Geometry::mydimension>::rule(geometry.type(), integrationOrder);
282 for (const auto& qp : quad)
283 avgDist += distancePointSegment(geometry.global(qp.position()), a, b)*qp.weight()*geometry.integrationElement(qp.position());
284 return avgDist/geometry.volume();
285}
286
291template<class ctype, int dimWorld>
292static inline ctype distance(const Dune::FieldVector<ctype, dimWorld>& a,
293 const Dune::FieldVector<ctype, dimWorld>& b)
294{ return (a-b).two_norm(); }
295
300template<class ctype, int dimWorld>
301static inline ctype squaredDistance(const Dune::FieldVector<ctype, dimWorld>& a,
302 const Dune::FieldVector<ctype, dimWorld>& b)
303{ return (a-b).two_norm2(); }
304
305
306namespace Detail {
307
308// helper struct to compute distance between two geometries, specialized below
309template<class Geo1, class Geo2,
310 int dimWorld = Geo1::coorddimension,
311 int dim1 = Geo1::mydimension, int dim2 = Geo2::mydimension>
313{
314 static_assert(Geo1::coorddimension == Geo2::coorddimension, "Geometries have to have the same coordinate dimensions");
315 static auto distance(const Geo1& geo1, const Geo2& geo2)
316 {
317 DUNE_THROW(Dune::NotImplemented, "Geometry distance computation not implemented for dimworld = "
318 << dimWorld << ", dim1 = " << dim1 << ", dim2 = " << dim2);
319 }
320};
321
322// distance point-point
323template<class Geo1, class Geo2, int dimWorld>
324struct GeometrySquaredDistance<Geo1, Geo2, dimWorld, 0, 0>
325{
326 static_assert(Geo1::coorddimension == Geo2::coorddimension, "Geometries have to have the same coordinate dimensions");
327 static auto distance(const Geo1& geo1, const Geo2& geo2)
328 { return Dumux::squaredDistance(geo1.corner(0), geo2.corner(0)); }
329};
330
331// distance segment-point
332template<class Geo1, class Geo2, int dimWorld>
333struct GeometrySquaredDistance<Geo1, Geo2, dimWorld, 1, 0>
334{
335 static_assert(Geo1::coorddimension == Geo2::coorddimension, "Geometries have to have the same coordinate dimensions");
336 static auto distance(const Geo1& geo1, const Geo2& geo2)
337 { return squaredDistancePointSegment(geo2.corner(0), geo1); }
338};
339
340// distance point-segment
341template<class Geo1, class Geo2, int dimWorld>
342struct GeometrySquaredDistance<Geo1, Geo2, dimWorld, 0, 1>
343{
344 static_assert(Geo1::coorddimension == Geo2::coorddimension, "Geometries have to have the same coordinate dimensions");
345 static auto distance(const Geo1& geo1, const Geo2& geo2)
346 { return squaredDistancePointSegment(geo1.corner(0), geo2); }
347};
348
349// distance point-polygon
350template<class Geo1, class Geo2, int dimWorld>
351struct GeometrySquaredDistance<Geo1, Geo2, dimWorld, 0, 2>
352{
353 static_assert(Geo1::coorddimension == Geo2::coorddimension, "Geometries have to have the same coordinate dimensions");
354 static inline auto distance(const Geo1& geo1, const Geo2& geo2)
355 { return squaredDistancePointPolygon(geo1.corner(0), geo2); }
356};
357
358// distance polygon-point
359template<class Geo1, class Geo2, int dimWorld>
360struct GeometrySquaredDistance<Geo1, Geo2, dimWorld, 2, 0>
361{
362 static_assert(Geo1::coorddimension == Geo2::coorddimension, "Geometries have to have the same coordinate dimensions");
363 static inline auto distance(const Geo1& geo1, const Geo2& geo2)
364 { return squaredDistancePointPolygon(geo2.corner(0), geo1); }
365};
366
367} // end namespace Detail
368
373template<class Geo1, class Geo2>
374static inline auto squaredDistance(const Geo1& geo1, const Geo2& geo2)
376
381template<class Geo1, class Geo2>
382static inline auto distance(const Geo1& geo1, const Geo2& geo2)
383{ using std::sqrt; return sqrt(squaredDistance(geo1, geo2)); }
384
385
387namespace Detail {
388
394template<class EntitySet, class ctype, int dimworld,
395 typename std::enable_if_t<(EntitySet::Entity::Geometry::mydimension > 0), int> = 0>
396void closestEntity(const Dune::FieldVector<ctype, dimworld>& point,
397 const BoundingBoxTree<EntitySet>& tree,
398 std::size_t node,
399 ctype& minSquaredDistance,
400 std::size_t& eIdx)
401{
402 // Get the bounding box for the current node
403 const auto& bBox = tree.getBoundingBoxNode(node);
404
405 // If bounding box is outside radius, then don't search further
407 point, tree.getBoundingBoxCoordinates(node)
408 );
409
410 // do not continue if the AABB is further away than the current minimum
411 if (squaredDistance > minSquaredDistance) return;
412
413 // If the bounding box is a leaf, update distance and index with primitive test
414 else if (tree.isLeaf(bBox, node))
415 {
416 const std::size_t entityIdx = bBox.child1;
417 const auto squaredDistance = [&]{
418 const auto geometry = tree.entitySet().entity(entityIdx).geometry();
419 if constexpr (EntitySet::Entity::Geometry::mydimension == 2)
420 return squaredDistancePointPolygon(point, geometry);
421 else if constexpr (EntitySet::Entity::Geometry::mydimension == 1)
422 return squaredDistancePointSegment(point, geometry);
423 else
424 DUNE_THROW(Dune::NotImplemented, "squaredDistance to entity with dim>2");
425 }();
426
427 if (squaredDistance < minSquaredDistance)
428 {
429 eIdx = entityIdx;
430 minSquaredDistance = squaredDistance;
431 }
432 }
433
434 // Check the children nodes recursively
435 else
436 {
437 closestEntity(point, tree, bBox.child0, minSquaredDistance, eIdx);
438 closestEntity(point, tree, bBox.child1, minSquaredDistance, eIdx);
439 }
440}
441
447template<class EntitySet, class ctype, int dimworld,
448 typename std::enable_if_t<(EntitySet::Entity::Geometry::mydimension == 0), int> = 0>
449void closestEntity(const Dune::FieldVector<ctype, dimworld>& point,
450 const BoundingBoxTree<EntitySet>& tree,
451 std::size_t node,
452 ctype& minSquaredDistance,
453 std::size_t& eIdx)
454{
455 // Get the bounding box for the current node
456 const auto& bBox = tree.getBoundingBoxNode(node);
457
458 // If the bounding box is a leaf, update distance and index with primitive test
459 if (tree.isLeaf(bBox, node))
460 {
461 const std::size_t entityIdx = bBox.child1;
462 const auto& p = tree.entitySet().entity(entityIdx).geometry().corner(0);
463 const auto squaredDistance = (p-point).two_norm2();
464
465 if (squaredDistance < minSquaredDistance)
466 {
467 eIdx = entityIdx;
468 minSquaredDistance = squaredDistance;
469 }
470 }
471
472 // Check the children nodes recursively
473 else
474 {
475 // If bounding box is outside radius, then don't search further
477 point, tree.getBoundingBoxCoordinates(node)
478 );
479
480 // do not continue if the AABB is further away than the current minimum
481 if (squaredDistance > minSquaredDistance) return;
482
483 closestEntity(point, tree, bBox.child0, minSquaredDistance, eIdx);
484 closestEntity(point, tree, bBox.child1, minSquaredDistance, eIdx);
485 }
486}
487
488} // end namespace Detail
489
503template<class EntitySet, class ctype, int dimworld>
504std::pair<ctype, std::size_t> closestEntity(const Dune::FieldVector<ctype, dimworld>& point,
505 const BoundingBoxTree<EntitySet>& tree,
506 ctype minSquaredDistance = std::numeric_limits<ctype>::max())
507{
508 std::size_t eIdx = 0;
509 Detail::closestEntity(point, tree, tree.numBoundingBoxes() - 1, minSquaredDistance, eIdx);
510 using std::sqrt;
511 return { minSquaredDistance, eIdx };
512}
513
518template<class EntitySet, class ctype, int dimworld>
519ctype squaredDistance(const Dune::FieldVector<ctype, dimworld>& point,
520 const BoundingBoxTree<EntitySet>& tree,
521 ctype minSquaredDistance = std::numeric_limits<ctype>::max())
522{
523 return closestEntity(point, tree, minSquaredDistance).first;
524}
525
530template<class EntitySet, class ctype, int dimworld>
531ctype distance(const Dune::FieldVector<ctype, dimworld>& point,
532 const BoundingBoxTree<EntitySet>& tree,
533 ctype minSquaredDistance = std::numeric_limits<ctype>::max())
534{
535 using std::sqrt;
536 return sqrt(squaredDistance(point, tree, minSquaredDistance));
537}
538
539} // end namespace Dumux
540
541#endif
Define some often used mathematical functions.
An axis-aligned bounding box volume hierarchy for dune grids.
static ctype distance(const Dune::FieldVector< ctype, dimWorld > &a, const Dune::FieldVector< ctype, dimWorld > &b)
Compute the shortest distance between two points.
Definition: distance.hh:292
Vector normal(const Vector &v)
Create a vector normal to the given one (v is expected to be non-zero)
Definition: normal.hh:36
static Geometry::ctype distancePointPolygon(const typename Geometry::GlobalCoordinate &p, const Geometry &geometry)
Compute the shortest distance from a point to a given polygon geometry.
Definition: distance.hh:266
static Point::value_type distancePointSegment(const Point &p, const Point &a, const Point &b)
Compute the distance from a point to the segment connecting the points a and b.
Definition: distance.hh:145
static Point::value_type squaredDistancePointTriangle(const Point &p, const Point &a, const Point &b, const Point &c)
Compute the shortest squared distance from a point to the triangle connecting the points a,...
Definition: distance.hh:164
static Point::value_type squaredDistancePointLine(const Point &p, const Point &a, const Point &b)
Compute the squared distance from a point to a line through the points a and b.
Definition: distance.hh:56
static Point::value_type distancePointTriangle(const Point &p, const Point &a, const Point &b, const Point &c)
Compute the shortest distance from a point to the triangle connecting the points a,...
Definition: distance.hh:221
static Geometry::ctype squaredDistancePointPolygon(const typename Geometry::GlobalCoordinate &p, const Geometry &geometry)
Compute the shortest squared distance from a point to a given polygon geometry.
Definition: distance.hh:240
static Point::value_type squaredDistancePointSegment(const Point &p, const Point &a, const Point &b)
Compute the squared distance from a point to the segment connecting the points a and b.
Definition: distance.hh:107
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:301
std::pair< ctype, std::size_t > closestEntity(const Dune::FieldVector< ctype, dimworld > &point, const BoundingBoxTree< EntitySet > &tree, ctype minSquaredDistance=std::numeric_limits< ctype >::max())
Compute the closest entity in an AABB tree to a point (index and shortest squared distance)
Definition: distance.hh:504
static Point::value_type distancePointLine(const Point &p, const Point &a, const Point &b)
Compute the distance from a point to a line through the points a and b.
Definition: distance.hh:87
static Geometry::ctype averageDistanceSegmentGeometry(const typename Geometry::GlobalCoordinate &a, const typename Geometry::GlobalCoordinate &b, const Geometry &geometry, std::size_t integrationOrder=2)
Compute the average distance from a segment to a geometry by integration.
Definition: distance.hh:275
static Geometry::ctype averageDistancePointGeometry(const typename Geometry::GlobalCoordinate &p, const Geometry &geometry, std::size_t integrationOrder=2)
Compute the average distance from a point to a geometry by integration.
Definition: distance.hh:39
void closestEntity(const Dune::FieldVector< ctype, dimworld > &point, const BoundingBoxTree< EntitySet > &tree, std::size_t node, ctype &minSquaredDistance, std::size_t &eIdx)
Compute the closest entity in an AABB tree (index and shortest squared distance) recursively.
Definition: distance.hh:396
Dune::FieldVector< Scalar, 3 > crossProduct(const Dune::FieldVector< Scalar, 3 > &vec1, const Dune::FieldVector< Scalar, 3 > &vec2)
Cross product of two vectors in three-dimensional Euclidean space.
Definition: math.hh:654
constexpr int sign(const ValueType &value) noexcept
Sign or signum function.
Definition: math.hh:641
Definition: adapt.hh:29
ctype squaredDistancePointBoundingBox(const Dune::FieldVector< ctype, dimworld > &point, const ctype *b)
Compute squared distance between point and bounding box.
Definition: boundingboxtree.hh:420
An axis-aligned bounding box volume tree implementation.
Definition: boundingboxtree.hh:66
const ctype * getBoundingBoxCoordinates(std::size_t nodeIdx) const
Get an existing bounding box for a given node.
Definition: boundingboxtree.hh:145
bool isLeaf(const BoundingBoxNode &node, std::size_t nodeIdx) const
Definition: boundingboxtree.hh:154
const EntitySet & entitySet() const
the entity set this tree was built with
Definition: boundingboxtree.hh:133
std::size_t numBoundingBoxes() const
Get the number of bounding boxes currently in the tree.
Definition: boundingboxtree.hh:149
const BoundingBoxNode & getBoundingBoxNode(std::size_t nodeIdx) const
Interface to be used by other bounding box trees.
Definition: boundingboxtree.hh:141
Definition: distance.hh:313
static auto distance(const Geo1 &geo1, const Geo2 &geo2)
Definition: distance.hh:315
static auto distance(const Geo1 &geo1, const Geo2 &geo2)
Definition: distance.hh:327
static auto distance(const Geo1 &geo1, const Geo2 &geo2)
Definition: distance.hh:336
static auto distance(const Geo1 &geo1, const Geo2 &geo2)
Definition: distance.hh:345
static auto distance(const Geo1 &geo1, const Geo2 &geo2)
Definition: distance.hh:354
static auto distance(const Geo1 &geo1, const Geo2 &geo2)
Definition: distance.hh:363