GCC Code Coverage Report


Directory: ../../../builds/dumux-repositories/
File: dumux/dumux/geometry/geometryintersection.hh
Date: 2025-04-12 19:19:20
Exec Total Coverage
Lines: 497 507 98.0%
Functions: 110 110 100.0%
Branches: 826 1703 48.5%

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-FileCopyrightText: 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 A class for collision detection of two geometries
11 * and computation of intersection corners
12 */
13 #ifndef DUMUX_GEOMETRY_INTERSECTION_HH
14 #define DUMUX_GEOMETRY_INTERSECTION_HH
15
16 #include <tuple>
17
18 #include <dune/common/exceptions.hh>
19 #include <dune/common/promotiontraits.hh>
20 #include <dune/geometry/multilineargeometry.hh>
21 #include <dune/geometry/referenceelements.hh>
22
23 #include <dumux/common/math.hh>
24 #include <dumux/geometry/intersectspointgeometry.hh>
25 #include <dumux/geometry/grahamconvexhull.hh>
26 #include <dumux/geometry/boundingboxtree.hh>
27
28 namespace Dumux {
29 namespace IntersectionPolicy {
30
31 //! Policy structure for point-like intersections
32 template<class ct, int dw>
33 struct PointPolicy
34 {
35 using ctype = ct;
36 using Point = Dune::FieldVector<ctype, dw>;
37
38 static constexpr int dimWorld = dw;
39 static constexpr int dimIntersection = 0;
40 using Intersection = Point;
41 };
42
43 //! Policy structure for segment-like intersections
44 template<class ct, int dw>
45 struct SegmentPolicy
46 {
47 using ctype = ct;
48 using Point = Dune::FieldVector<ctype, dw>;
49 using Segment = std::array<Point, 2>;
50
51 static constexpr int dimWorld = dw;
52 static constexpr int dimIntersection = 1;
53 using Intersection = Segment;
54 };
55
56 //! Policy structure for polygon-like intersections
57 template<class ct, int dw>
58 struct PolygonPolicy
59 {
60 using ctype = ct;
61 using Point = Dune::FieldVector<ctype, dw>;
62 using Polygon = std::vector<Point>;
63
64 static constexpr int dimWorld = dw;
65 static constexpr int dimIntersection = 2;
66 using Intersection = Polygon;
67 };
68
69 //! Policy structure for polyhedron-like intersections
70 template<class ct, int dw>
71 struct PolyhedronPolicy
72 {
73 using ctype = ct;
74 using Point = Dune::FieldVector<ctype, dw>;
75 using Polyhedron = std::vector<Point>;
76
77 static constexpr int dimWorld = dw;
78 static constexpr int dimIntersection = 3;
79 using Intersection = Polyhedron;
80 };
81
82 //! default policy chooser class
83 template<class Geometry1, class Geometry2>
84 class DefaultPolicyChooser
85 {
86 static constexpr int dimworld = Geometry1::coorddimension;
87 static constexpr int isDim = std::min( int(Geometry1::mydimension), int(Geometry2::mydimension) );
88 static_assert(dimworld == int(Geometry2::coorddimension),
89 "Geometries must have the same coordinate dimension!");
90 static_assert(int(Geometry1::mydimension) <= 3 && int(Geometry2::mydimension) <= 3,
91 "Geometries must have dimension 3 or less.");
92 using ctype = typename Dune::PromotionTraits<typename Geometry1::ctype, typename Geometry2::ctype>::PromotedType;
93
94 using DefaultPolicies = std::tuple<PointPolicy<ctype, dimworld>,
95 SegmentPolicy<ctype, dimworld>,
96 PolygonPolicy<ctype, dimworld>,
97 PolyhedronPolicy<ctype, dimworld>>;
98 public:
99 using type = std::tuple_element_t<isDim, DefaultPolicies>;
100 };
101
102 //! Helper alias to define the default intersection policy
103 template<class Geometry1, class Geometry2>
104 using DefaultPolicy = typename DefaultPolicyChooser<Geometry1, Geometry2>::type;
105
106 } // end namespace IntersectionPolicy
107
108 namespace Detail {
109
110 /*!
111 * \ingroup Geometry
112 * \brief Algorithm to find segment-like intersections of a polygon/polyhedron with a
113 * segment. The result is stored in the form of the local coordinates tfirst
114 * and tlast on the segment geo1.
115 * \param geo1 the first geometry
116 * \param geo2 the second geometry (dimGeo2 < dimGeo1)
117 * \param baseEps the base epsilon used for floating point comparisons
118 * \param tfirst stores the local coordinate of beginning of intersection segment
119 * \param tlast stores the local coordinate of the end of intersection segment
120 * \param getFacetCornerIndices Function to obtain the facet corner indices on geo1
121 * \param computeNormal Function to obtain the normal vector on a facet on geo1
122 */
123 template< class Geo1, class Geo2, class ctype,
124 class GetFacetCornerIndices, class ComputeNormalFunction >
125 787323 bool computeSegmentIntersection(const Geo1& geo1, const Geo2& geo2, ctype baseEps,
126 ctype& tfirst, ctype& tlast,
127 const GetFacetCornerIndices& getFacetCornerIndices,
128 const ComputeNormalFunction& computeNormal)
129 {
130 static_assert(int(Geo2::mydimension) == 1, "Geometry2 must be a segment");
131 static_assert(int(Geo1::mydimension) > int(Geo2::mydimension),
132 "Dimension of Geometry1 must be higher than that of Geometry2");
133
134 787323 const auto a = geo2.corner(0);
135 787323 const auto b = geo2.corner(1);
136 787323 const auto d = b - a;
137
138 // The initial interval is the whole segment.
139 // Afterwards we start clipping the interval
140 // at the intersections with the facets of geo1
141 787323 tfirst = 0.0;
142 787323 tlast = 1.0;
143
144 787323 const auto facets = getFacetCornerIndices(geo1);
145
2/2
✓ Branch 0 taken 1651073 times.
✓ Branch 1 taken 133802 times.
2434648 for (const auto& f : facets)
146 {
147
1/2
✓ Branch 1 taken 25123 times.
✗ Branch 2 not taken.
2289051 const auto n = computeNormal(f);
148
149
4/5
✓ Branch 1 taken 629111 times.
✗ Branch 2 not taken.
✓ Branch 3 taken 75369 times.
✓ Branch 4 taken 25123 times.
✓ Branch 0 taken 1811964 times.
6882741 const auto c0 = geo1.corner(f[0]);
150 2289051 const ctype denom = n*d;
151
1/2
✓ Branch 1 taken 25123 times.
✗ Branch 2 not taken.
2314174 const ctype dist = n*(a-c0);
152
153 // use first edge of the facet to scale eps
154
2/4
✓ Branch 1 taken 25123 times.
✗ Branch 2 not taken.
✓ Branch 4 taken 25123 times.
✗ Branch 5 not taken.
6862368 const auto edge1 = geo1.corner(f[1]) - geo1.corner(f[0]);
155
2/2
✓ Branch 0 taken 404804 times.
✓ Branch 1 taken 1246269 times.
2289051 const ctype eps = baseEps*edge1.two_norm();
156
157 // if denominator is zero the segment in parallel to the edge.
158 // If the distance is positive there is no intersection
159 using std::abs;
160
2/2
✓ Branch 0 taken 404804 times.
✓ Branch 1 taken 1246269 times.
2289051 if (abs(denom) < eps)
161 {
162
2/2
✓ Branch 0 taken 335436 times.
✓ Branch 1 taken 69368 times.
445017 if (dist > eps)
163 641726 return false;
164 }
165 else // not parallel: compute line-line intersection
166 {
167
2/2
✓ Branch 0 taken 699855 times.
✓ Branch 1 taken 546414 times.
1844034 const ctype t = -dist / denom;
168 // if entering half space cut tfirst if t is larger
169 using std::signbit;
170
2/2
✓ Branch 0 taken 699855 times.
✓ Branch 1 taken 546414 times.
1844034 if (signbit(denom))
171 {
172
2/2
✓ Branch 0 taken 412265 times.
✓ Branch 1 taken 287590 times.
1041041 if (t > tfirst)
173 654076 tfirst = t;
174 }
175 // if exiting half space cut tlast if t is smaller
176 else
177 {
178
2/2
✓ Branch 0 taken 384524 times.
✓ Branch 1 taken 161890 times.
802993 if (t < tlast)
179 618329 tlast = t;
180 }
181 // there is no intersection of the interval is empty
182 // use unscaled epsilon since t is in local coordinates
183
2/2
✓ Branch 0 taken 856937 times.
✓ Branch 1 taken 389332 times.
1844034 if (tfirst > tlast - baseEps)
184 return false;
185 }
186 }
187
188 // If we made it until here an intersection exists.
189 return true;
190 787323 }
191
192 } // end namespace Detail
193
194 /*!
195 * \ingroup Geometry
196 * \brief A class for geometry collision detection and intersection calculation
197 * The class can be specialized for combinations of dimworld, dim1, dim2, where
198 * dimworld is the world dimension embedding a grid of dim1 and a grid of dim2.
199 */
200 template
201 <class Geometry1, class Geometry2,
202 class Policy = IntersectionPolicy::DefaultPolicy<Geometry1, Geometry2>,
203 int dimworld = Geometry1::coorddimension,
204 int dim1 = Geometry1::mydimension,
205 int dim2 = Geometry2::mydimension>
206 class GeometryIntersection
207 {
208 static constexpr int dimWorld = Policy::dimWorld;
209
210 public:
211 using ctype = typename Policy::ctype;
212 using Point = typename Policy::Point;
213 using Intersection = typename Policy::Intersection;
214
215 //! Determine if the two geometries intersect and compute the intersection geometry
216 static bool intersection(const Geometry1& geo1, const Geometry2& geo2, Intersection& intersection)
217 {
218 static_assert(dimworld == Geometry2::coorddimension, "Can only intersect geometries of same coordinate dimension");
219 DUNE_THROW(Dune::NotImplemented, "Geometry intersection detection with intersection computation not implemented for dimworld = "
220 << dimworld << ", dim1 = " << dim1 << ", dim2 = " << dim2);
221 }
222 };
223
224 /*!
225 * \ingroup Geometry
226 * \brief A class for segment--segment intersection in 2d space
227 */
228 template <class Geometry1, class Geometry2, class Policy>
229 class GeometryIntersection<Geometry1, Geometry2, Policy, 2, 1, 1>
230 {
231 enum { dimworld = 2 };
232 enum { dim1 = 1 };
233 enum { dim2 = 1 };
234
235 // base epsilon for floating point comparisons
236 static constexpr typename Policy::ctype eps_ = 1.5e-7;
237
238 public:
239 using ctype = typename Policy::ctype;
240 using Point = typename Policy::Point;
241 using Intersection = typename Policy::Intersection;
242
243 /*!
244 * \brief Colliding two segments
245 * \param geo1/geo2 The geometries to intersect
246 * \param intersection The intersection point
247 * \note This overload is used when point-like intersections are seeked
248 */
249 template<class P = Policy, std::enable_if_t<P::dimIntersection == 0, int> = 0>
250 1898288 static bool intersection(const Geometry1& geo1, const Geometry2& geo2, Intersection& intersection)
251 {
252 static_assert(int(dimworld) == int(Geometry2::coorddimension), "Can only collide geometries of same coordinate dimension");
253
254 1898288 const auto v1 = geo1.corner(1) - geo1.corner(0);
255 1898288 const auto v2 = geo2.corner(1) - geo2.corner(0);
256 3796576 const auto ac = geo2.corner(0) - geo1.corner(0);
257
258 1898288 auto n2 = Point({-1.0*v2[1], v2[0]});
259
2/2
✓ Branch 0 taken 3796576 times.
✓ Branch 1 taken 1898288 times.
7593152 n2 /= n2.two_norm();
260
261 // compute distance of first corner on geo2 to line1
262
2/2
✓ Branch 0 taken 3796576 times.
✓ Branch 1 taken 1898288 times.
5694864 const auto dist12 = n2*ac;
263
264 // first check parallel segments
265 using std::abs;
266 using std::sqrt;
267
268 1898288 const auto v1Norm2 = v1.two_norm2();
269 1898288 const auto eps = eps_*sqrt(v1Norm2);
270 1898288 const auto eps2 = eps_*v1Norm2;
271
272
2/2
✓ Branch 0 taken 948960 times.
✓ Branch 1 taken 949328 times.
1898288 const auto sp = n2*v1;
273
2/2
✓ Branch 0 taken 948960 times.
✓ Branch 1 taken 949328 times.
1898288 if (abs(sp) < eps)
274 {
275
2/2
✓ Branch 0 taken 735232 times.
✓ Branch 1 taken 213728 times.
948960 if (abs(dist12) > eps)
276 return false;
277
278 // point intersection can only be one of the corners
279
2/2
✓ Branch 0 taken 8 times.
✓ Branch 1 taken 213720 times.
213728 if ( (v1*v2) < 0.0 )
280 {
281
2/2
✓ Branch 0 taken 4 times.
✓ Branch 1 taken 4 times.
8 if ( ac.two_norm2() < eps2 )
282 4 { intersection = geo2.corner(0); return true; }
283
284
1/2
✗ Branch 2 not taken.
✓ Branch 3 taken 4 times.
12 if ( (geo2.corner(1) - geo1.corner(1)).two_norm2() < eps2 )
285 { intersection = geo2.corner(1); return true; }
286 }
287 else
288 {
289
2/2
✓ Branch 2 taken 63896 times.
✓ Branch 3 taken 149824 times.
641160 if ( (geo2.corner(1) - geo1.corner(0)).two_norm2() < eps2 )
290 63896 { intersection = geo2.corner(1); return true; }
291
292
2/2
✓ Branch 2 taken 63900 times.
✓ Branch 3 taken 85924 times.
449472 if ( (geo2.corner(0) - geo1.corner(1)).two_norm2() < eps2 )
293 63900 { intersection = geo2.corner(0); return true; }
294 }
295
296 // no intersection
297 85928 return false;
298 }
299
300 // intersection point on v1 in local coords
301 949328 const auto t1 = dist12 / sp;
302
303 // check if the local coords are valid
304
4/4
✓ Branch 0 taken 152092 times.
✓ Branch 1 taken 797236 times.
✓ Branch 2 taken 152144 times.
✓ Branch 3 taken 645092 times.
949328 if (t1 < -1.0*eps_ || t1 > 1.0 + eps_)
305 return false;
306
307 // compute global coordinates
308 645092 auto isPoint = geo1.global(t1);
309
310 // check if point is in bounding box of v2
311 645092 const auto c = geo2.corner(0);
312
2/2
✓ Branch 1 taken 60 times.
✓ Branch 2 taken 645032 times.
645092 const auto d = geo2.corner(1);
313
314 using std::min; using std::max;
315
10/10
✓ Branch 0 taken 60 times.
✓ Branch 1 taken 645032 times.
✓ Branch 2 taken 8 times.
✓ Branch 3 taken 645084 times.
✓ Branch 4 taken 322552 times.
✓ Branch 5 taken 322540 times.
✓ Branch 6 taken 322580 times.
✓ Branch 7 taken 322512 times.
✓ Branch 8 taken 342544 times.
✓ Branch 9 taken 302548 times.
1290292 std::array<ctype, 4> bBox({ min(c[0], d[0]), min(c[1], d[1]), max(c[0], d[0]), max(c[1], d[1]) });
316
317
2/2
✓ Branch 0 taken 342544 times.
✓ Branch 1 taken 302548 times.
645092 if ( intersectsPointBoundingBox(isPoint, bBox.data()) )
318 {
319 302548 intersection = std::move(isPoint);
320 302548 return true;
321 }
322
323 return false;
324 }
325
326 /*!
327 * \brief Colliding two segments
328 * \param geo1/geo2 The geometries to intersect
329 * \param intersection Container to store corners of intersection segment
330 * \note this overload is used when segment-like intersections are seeked
331 */
332 template<class P = Policy, std::enable_if_t<P::dimIntersection == 1, int> = 0>
333 70 static bool intersection(const Geometry1& geo1, const Geometry2& geo2, Intersection& intersection)
334 {
335 static_assert(int(dimworld) == int(Geometry2::coorddimension), "Can only collide geometries of same coordinate dimension");
336
337 70 const auto& a = geo1.corner(0);
338 70 const auto& b = geo1.corner(1);
339 70 const auto ab = b - a;
340
341 70 const auto& p = geo2.corner(0);
342 70 const auto& q = geo2.corner(1);
343 70 const auto pq = q - p;
344 70 Dune::FieldVector<ctype, dimworld> n2{-pq[1], pq[0]};
345
346 using std::max;
347 70 const auto abNorm2 = ab.two_norm2();
348
2/2
✓ Branch 0 taken 20 times.
✓ Branch 1 taken 50 times.
70 const auto pqNorm2 = pq.two_norm2();
349 70 const auto eps2 = eps_*max(abNorm2, pqNorm2);
350
351 // non-parallel segments do not intersect in a segment.
352 using std::abs;
353
2/2
✓ Branch 0 taken 4 times.
✓ Branch 1 taken 66 times.
70 if (abs(n2*ab) > eps2)
354 return false;
355
356 // check if the segments lie on the same line
357 66 const auto ap = p - a;
358
2/2
✓ Branch 0 taken 4 times.
✓ Branch 1 taken 62 times.
66 if (abs(ap*n2) > eps2)
359 return false;
360
361 // compute scaled local coordinates of corner 1/2 of segment2 on segment1
362 62 auto t1 = ab*ap;
363 62 auto t2 = ab*(q - a);
364
365 using std::swap;
366
2/2
✓ Branch 0 taken 33 times.
✓ Branch 1 taken 29 times.
62 if (t1 > t2)
367 33 swap(t1, t2);
368
369 using std::clamp;
370
2/2
✓ Branch 0 taken 16 times.
✓ Branch 1 taken 46 times.
62 t1 = clamp(t1, 0.0, abNorm2);
371
2/2
✓ Branch 0 taken 4 times.
✓ Branch 1 taken 58 times.
62 t2 = clamp(t2, 0.0, abNorm2);
372
373
2/2
✓ Branch 0 taken 32 times.
✓ Branch 1 taken 30 times.
62 if (abs(t2-t1) < eps2)
374 return false;
375
376 32 intersection = Intersection({geo1.global(t1/abNorm2), geo1.global(t2/abNorm2)});
377 30 return true;
378 }
379 };
380
381 /*!
382 * \ingroup Geometry
383 * \brief A class for polygon--segment intersection in 2d space
384 */
385 template <class Geometry1, class Geometry2, class Policy>
386 class GeometryIntersection<Geometry1, Geometry2, Policy, 2, 2, 1>
387 {
388 enum { dimworld = 2 };
389 enum { dim1 = 2 };
390 enum { dim2 = 1 };
391
392 public:
393 using ctype = typename Policy::ctype;
394 using Point = typename Policy::Point;
395 using Intersection = typename Policy::Intersection;
396
397 private:
398 static constexpr ctype eps_ = 1.5e-7; // base epsilon for floating point comparisons
399
400 public:
401 /*!
402 * \brief Colliding segment and convex polygon
403 * \param geo1/geo2 The geometries to intersect
404 * \param intersection If the geometries collide intersection holds the
405 * corner points of the intersection object in global coordinates.
406 * \note This overload is used when segment-like intersections are seeked.
407 */
408 template<class P = Policy, std::enable_if_t<P::dimIntersection == 1, int> = 0>
409 4750 static bool intersection(const Geometry1& geo1, const Geometry2& geo2, Intersection& intersection)
410 {
411 static_assert(int(dimworld) == int(Geometry2::coorddimension), "Can only collide geometries of same coordinate dimension");
412
413 ctype tfirst, tlast;
414
2/2
✓ Branch 1 taken 500 times.
✓ Branch 2 taken 4250 times.
4750 if (intersect_(geo1, geo2, tfirst, tlast))
415 {
416 // the intersection exists. Export the intersections geometry now:
417 // s(t) = a + t(b-a) in [tfirst, tlast]
418 500 intersection = Intersection({geo2.global(tfirst), geo2.global(tlast)});
419 500 return true;
420 }
421
422 return false;
423 }
424
425 /*!
426 * \brief Colliding segment and convex polygon
427 * \param geo1/geo2 The geometries to intersect
428 * \param intersection If the geometries collide intersection holds the
429 * corner points of the intersection object in global coordinates.
430 * \note This overload is used when point-like intersections are seeked.
431 */
432 template<class P = Policy, std::enable_if_t<P::dimIntersection == 0, int> = 0>
433 24 static bool intersection(const Geometry1& geo1, const Geometry2& geo2, typename P::Intersection& intersection)
434 {
435 static_assert(int(dimworld) == int(Geometry2::coorddimension), "Can only collide geometries of same coordinate dimension");
436
437 ctype tfirst, tlast;
438
2/2
✓ Branch 1 taken 4 times.
✓ Branch 2 taken 20 times.
24 if (!intersect_(geo1, geo2, tfirst, tlast))
439 {
440 // if start & end point are same, the intersection is a point
441 using std::abs;
442
1/2
✓ Branch 0 taken 4 times.
✗ Branch 1 not taken.
4 if ( tfirst > tlast - eps_ )
443 {
444 4 intersection = Intersection(geo2.global(tfirst));
445 4 return true;
446 }
447 }
448
449 return false;
450 }
451
452 private:
453 /*!
454 * \brief Obtain local coordinates of start/end point of the intersecting segment.
455 */
456 4822 static bool intersect_(const Geometry1& geo1, const Geometry2& geo2, ctype& tfirst, ctype& tlast)
457 {
458 // lambda to obtain the facet corners on geo1
459 4774 auto getFacetCorners = [] (const Geometry1& geo1)
460 {
461
1/2
✓ Branch 1 taken 4726 times.
✗ Branch 2 not taken.
4774 std::vector< std::array<int, 2> > facetCorners;
462
4/6
✓ Branch 0 taken 13 times.
✓ Branch 1 taken 11 times.
✗ Branch 2 not taken.
✓ Branch 3 taken 13 times.
✓ Branch 4 taken 11 times.
✗ Branch 5 not taken.
48 switch (geo1.corners())
463 {
464 26 case 4: // quadrilateral
465
2/5
✓ Branch 1 taken 4739 times.
✗ Branch 2 not taken.
✗ Branch 3 not taken.
✓ Branch 4 taken 13 times.
✗ Branch 5 not taken.
4752 facetCorners = {{0, 2}, {3, 1}, {1, 0}, {2, 3}};
466 26 break;
467 22 case 3: // triangle
468
2/8
✓ Branch 1 taken 11 times.
✗ Branch 2 not taken.
✗ Branch 3 not taken.
✗ Branch 4 not taken.
✓ Branch 6 taken 11 times.
✗ Branch 7 not taken.
✗ Branch 8 not taken.
✗ Branch 9 not taken.
22 facetCorners = {{1, 0}, {0, 2}, {2, 1}};
469 22 break;
470 default:
471
0/60
✗ Branch 1 not taken.
✗ Branch 2 not taken.
✗ Branch 4 not taken.
✗ Branch 5 not taken.
✗ Branch 7 not taken.
✗ Branch 8 not taken.
✗ Branch 10 not taken.
✗ Branch 11 not taken.
✗ Branch 13 not taken.
✗ Branch 14 not taken.
✗ Branch 16 not taken.
✗ Branch 17 not taken.
✗ Branch 19 not taken.
✗ Branch 20 not taken.
✗ Branch 22 not taken.
✗ Branch 23 not taken.
✗ Branch 25 not taken.
✗ Branch 26 not taken.
✗ Branch 29 not taken.
✗ Branch 30 not taken.
✗ Branch 32 not taken.
✗ Branch 33 not taken.
✗ Branch 36 not taken.
✗ Branch 37 not taken.
✗ Branch 39 not taken.
✗ Branch 40 not taken.
✗ Branch 42 not taken.
✗ Branch 43 not taken.
✗ Branch 45 not taken.
✗ Branch 46 not taken.
✗ Branch 52 not taken.
✗ Branch 53 not taken.
✗ Branch 55 not taken.
✗ Branch 56 not taken.
✗ Branch 58 not taken.
✗ Branch 59 not taken.
✗ Branch 61 not taken.
✗ Branch 62 not taken.
✗ Branch 64 not taken.
✗ Branch 65 not taken.
✗ Branch 67 not taken.
✗ Branch 68 not taken.
✗ Branch 70 not taken.
✗ Branch 71 not taken.
✗ Branch 73 not taken.
✗ Branch 74 not taken.
✗ Branch 76 not taken.
✗ Branch 77 not taken.
✗ Branch 80 not taken.
✗ Branch 81 not taken.
✗ Branch 83 not taken.
✗ Branch 84 not taken.
✗ Branch 87 not taken.
✗ Branch 88 not taken.
✗ Branch 90 not taken.
✗ Branch 91 not taken.
✗ Branch 93 not taken.
✗ Branch 94 not taken.
✗ Branch 96 not taken.
✗ Branch 97 not taken.
4726 DUNE_THROW(Dune::NotImplemented, "Collision of segment and geometry of type "
472 << geo1.type() << " with "<< geo1.corners() << " corners.");
473 }
474
475 4774 return facetCorners;
476 };
477
478 // lambda to obtain the normal on a facet
479 4822 const auto center1 = geo1.center();
480 21727 auto computeNormal = [&geo1, &center1] (const std::array<int, 2>& facetCorners)
481 {
482 16905 const auto c0 = geo1.corner(facetCorners[0]);
483 33642 const auto c1 = geo1.corner(facetCorners[1]);
484 16905 const auto edge = c1 - c0;
485
486 16905 Dune::FieldVector<ctype, dimworld> n({-1.0*edge[1], edge[0]});
487 16905 n /= n.two_norm();
488
489 // orientation of the element is not known
490 // make sure normal points outwards of element
491
2/4
✗ Branch 0 not taken.
✓ Branch 1 taken 16821 times.
✗ Branch 2 not taken.
✓ Branch 3 taken 84 times.
50715 if ( n*(center1-c0) > 0.0 )
492 16905 n *= -1.0;
493
494 16905 return n;
495 };
496
497 4822 return Detail::computeSegmentIntersection(geo1, geo2, eps_, tfirst, tlast, getFacetCorners, computeNormal);
498 }
499 };
500
501 /*!
502 * \ingroup Geometry
503 * \brief A class for segment--polygon intersection in 2d space
504 */
505 template <class Geometry1, class Geometry2, class Policy>
506 class GeometryIntersection<Geometry1, Geometry2, Policy, 2, 1, 2>
507 : public GeometryIntersection<Geometry2, Geometry1, Policy, 2, 2, 1>
508 {
509 using Base = GeometryIntersection<Geometry2, Geometry1, Policy, 2, 2, 1>;
510
511 public:
512 /*!
513 * \brief Colliding segment and convex polygon
514 * \param geo1/geo2 The geometries to intersect
515 * \param intersection If the geometries collide intersection holds the
516 * corner points of the intersection object in global coordinates.
517 * \note This forwards to the polygon-segment specialization with swapped arguments.
518 */
519 template<class P = Policy>
520 4428 static bool intersection(const Geometry1& geo1, const Geometry2& geo2, typename Base::Intersection& intersection)
521 {
522
1/2
✓ Branch 1 taken 4384 times.
✗ Branch 2 not taken.
4428 return Base::intersection(geo2, geo1, intersection);
523 }
524 };
525
526 /*!
527 * \ingroup Geometry
528 * \brief A class for polygon--polygon intersection in 2d space
529 */
530 template <class Geometry1, class Geometry2, class Policy>
531 class GeometryIntersection<Geometry1, Geometry2, Policy, 2, 2, 2>
532 {
533 enum { dimworld = 2 };
534 enum { dim1 = 2 };
535 enum { dim2 = 2 };
536
537 public:
538 using ctype = typename Policy::ctype;
539 using Point = typename Policy::Point;
540 using Intersection = typename Policy::Intersection;
541
542 private:
543 static constexpr ctype eps_ = 1.5e-7; // base epsilon for floating point comparisons
544
545 public:
546 /*!
547 * \brief Colliding two polygons
548 * \note First we find the vertex candidates for the intersection region as follows:
549 * Add polygon vertices that are inside the other polygon
550 * Add intersections of polygon edges
551 * Remove duplicate points from the list
552 * Compute the convex hull polygon
553 * Return a triangulation of that polygon as intersection
554 * \param geo1/geo2 The geometries to intersect
555 * \param intersection Container to store the corner points of the polygon (as convex hull)
556 * \note This overload is used when polygon like intersections are seeked
557 */
558 template<class P = Policy, std::enable_if_t<P::dimIntersection == 2, int> = 0>
559 196448 static bool intersection(const Geometry1& geo1, const Geometry2& geo2, Intersection& intersection)
560 {
561 static_assert(int(dimworld) == int(Geometry2::coorddimension), "Can only collide geometries of same coordinate dimension");
562
563 // the candidate intersection points
564
1/2
✓ Branch 1 taken 196188 times.
✗ Branch 2 not taken.
196448 std::vector<Point> points; points.reserve(6);
565
566 // add polygon1 corners that are inside polygon2
567
3/3
✓ Branch 0 taken 784336 times.
✓ Branch 1 taken 196396 times.
✓ Branch 2 taken 104 times.
982072 for (int i = 0; i < geo1.corners(); ++i)
568
5/6
✓ Branch 2 taken 300 times.
✗ Branch 3 not taken.
✓ Branch 4 taken 44 times.
✓ Branch 5 taken 76 times.
✓ Branch 0 taken 134472 times.
✓ Branch 1 taken 649876 times.
785624 if (intersectsPointGeometry(geo1.corner(i), geo2))
569
2/3
✓ Branch 1 taken 134472 times.
✓ Branch 2 taken 56 times.
✗ Branch 3 not taken.
134556 points.emplace_back(geo1.corner(i));
570
571
2/2
✓ Branch 0 taken 195412 times.
✓ Branch 1 taken 580 times.
196448 const auto numPoints1 = points.size();
572
2/2
✓ Branch 0 taken 195608 times.
✓ Branch 1 taken 580 times.
196448 if (numPoints1 != geo1.corners())
573 {
574 // add polygon2 corners that are inside polygon1
575
3/3
✓ Branch 0 taken 782288 times.
✓ Branch 1 taken 195692 times.
✓ Branch 2 taken 36 times.
979316 for (int i = 0; i < geo2.corners(); ++i)
576
6/6
✓ Branch 2 taken 120 times.
✓ Branch 3 taken 124 times.
✓ Branch 4 taken 180 times.
✓ Branch 5 taken 72 times.
✓ Branch 0 taken 511388 times.
✓ Branch 1 taken 270900 times.
783448 if (intersectsPointGeometry(geo2.corner(i), geo1))
577
2/3
✓ Branch 1 taken 511512 times.
✓ Branch 2 taken 48 times.
✗ Branch 3 not taken.
512260 points.emplace_back(geo2.corner(i));
578
579
2/2
✓ Branch 0 taken 195596 times.
✓ Branch 1 taken 12 times.
195868 if (points.empty())
580 return false;
581
582
2/2
✓ Branch 0 taken 118664 times.
✓ Branch 1 taken 76932 times.
195844 if (points.size() - numPoints1 != geo2.corners())
583 {
584
1/2
✓ Branch 1 taken 118628 times.
✗ Branch 2 not taken.
118800 const auto refElement1 = referenceElement(geo1);
585 118800 const auto refElement2 = referenceElement(geo2);
586
587 // add intersections of edges
588 using SegGeometry = Dune::MultiLinearGeometry<ctype, 1, dimworld>;
589 using PointPolicy = IntersectionPolicy::PointPolicy<ctype, dimworld>;
590
2/2
✓ Branch 1 taken 474580 times.
✓ Branch 2 taken 118664 times.
593884 for (int i = 0; i < refElement1.size(dim1-1); ++i)
591 {
592 475084 const auto localEdgeGeom1 = refElement1.template geometry<dim1-1>(i);
593
1/2
✓ Branch 0 taken 474580 times.
✗ Branch 1 not taken.
475084 const auto edge1 = SegGeometry( Dune::GeometryTypes::line,
594
1/2
✓ Branch 2 taken 228 times.
✗ Branch 3 not taken.
475432 std::vector<Point>( {geo1.global(localEdgeGeom1.corner(0)),
595
1/2
✓ Branch 1 taken 474352 times.
✗ Branch 2 not taken.
949820 geo1.global(localEdgeGeom1.corner(1))} ));
596
597
2/2
✓ Branch 1 taken 1898248 times.
✓ Branch 2 taken 474580 times.
2375348 for (int j = 0; j < refElement2.size(dim2-1); ++j)
598 {
599 1900264 const auto localEdgeGeom2 = refElement2.template geometry<dim2-1>(j);
600
1/2
✓ Branch 0 taken 1898248 times.
✗ Branch 1 not taken.
1900264 const auto edge2 = SegGeometry( Dune::GeometryTypes::line,
601
1/6
✓ Branch 2 taken 360 times.
✗ Branch 3 not taken.
✗ Branch 4 not taken.
✗ Branch 5 not taken.
✗ Branch 0 not taken.
✗ Branch 1 not taken.
1900624 std::vector<Point>( {geo2.global(localEdgeGeom2.corner(0)),
602
1/2
✓ Branch 1 taken 1897888 times.
✗ Branch 2 not taken.
3800168 geo2.global(localEdgeGeom2.corner(1))} ));
603
604 using EdgeTest = GeometryIntersection<SegGeometry, SegGeometry, PointPolicy>;
605 1900264 typename EdgeTest::Intersection edgeIntersection;
606
2/2
✓ Branch 1 taken 430324 times.
✓ Branch 2 taken 1467924 times.
1900264 if (EdgeTest::intersection(edge1, edge2, edgeIntersection))
607
1/2
✓ Branch 1 taken 430324 times.
✗ Branch 2 not taken.
430644 points.emplace_back(edgeIntersection);
608 }
609 }
610 }
611 }
612
613
1/2
✓ Branch 0 taken 196176 times.
✗ Branch 1 not taken.
196424 if (points.empty())
614 return false;
615
616 // remove duplicates
617 589128 const auto eps = (geo1.corner(0) - geo1.corner(1)).two_norm()*eps_;
618
12/48
✗ Branch 0 not taken.
✗ Branch 1 not taken.
✗ Branch 2 not taken.
✗ Branch 3 not taken.
✓ Branch 4 taken 315993 times.
✓ Branch 5 taken 855602 times.
✗ Branch 6 not taken.
✗ Branch 7 not taken.
✓ Branch 8 taken 368 times.
✓ Branch 9 taken 364 times.
✗ Branch 10 not taken.
✗ Branch 11 not taken.
✗ Branch 12 not taken.
✗ Branch 13 not taken.
✗ Branch 14 not taken.
✗ Branch 15 not taken.
✗ Branch 16 not taken.
✗ Branch 17 not taken.
✗ Branch 18 not taken.
✗ Branch 19 not taken.
✗ Branch 20 not taken.
✗ Branch 21 not taken.
✓ Branch 22 taken 308676 times.
✓ Branch 23 taken 570760 times.
✗ Branch 24 not taken.
✗ Branch 25 not taken.
✓ Branch 26 taken 136 times.
✓ Branch 27 taken 192 times.
✗ Branch 28 not taken.
✗ Branch 29 not taken.
✗ Branch 30 not taken.
✗ Branch 31 not taken.
✗ Branch 32 not taken.
✗ Branch 33 not taken.
✗ Branch 34 not taken.
✗ Branch 35 not taken.
✗ Branch 36 not taken.
✗ Branch 37 not taken.
✗ Branch 38 not taken.
✗ Branch 39 not taken.
✗ Branch 40 not taken.
✗ Branch 41 not taken.
✗ Branch 42 not taken.
✗ Branch 43 not taken.
✓ Branch 44 taken 372 times.
✓ Branch 45 taken 216 times.
✓ Branch 46 taken 112 times.
✓ Branch 47 taken 100 times.
2249315 std::sort(points.begin(), points.end(), [&eps](const auto& a, const auto& b) -> bool
619 {
620 using std::abs;
621
12/48
✗ Branch 0 not taken.
✗ Branch 1 not taken.
✗ Branch 2 not taken.
✗ Branch 3 not taken.
✓ Branch 4 taken 315993 times.
✓ Branch 5 taken 855602 times.
✗ Branch 6 not taken.
✗ Branch 7 not taken.
✓ Branch 8 taken 368 times.
✓ Branch 9 taken 364 times.
✗ Branch 10 not taken.
✗ Branch 11 not taken.
✗ Branch 12 not taken.
✗ Branch 13 not taken.
✗ Branch 14 not taken.
✗ Branch 15 not taken.
✗ Branch 16 not taken.
✗ Branch 17 not taken.
✗ Branch 18 not taken.
✗ Branch 19 not taken.
✗ Branch 20 not taken.
✗ Branch 21 not taken.
✓ Branch 22 taken 308676 times.
✓ Branch 23 taken 570760 times.
✗ Branch 24 not taken.
✗ Branch 25 not taken.
✓ Branch 26 taken 136 times.
✓ Branch 27 taken 192 times.
✗ Branch 28 not taken.
✗ Branch 29 not taken.
✗ Branch 30 not taken.
✗ Branch 31 not taken.
✗ Branch 32 not taken.
✗ Branch 33 not taken.
✗ Branch 34 not taken.
✗ Branch 35 not taken.
✗ Branch 36 not taken.
✗ Branch 37 not taken.
✗ Branch 38 not taken.
✗ Branch 39 not taken.
✗ Branch 40 not taken.
✗ Branch 41 not taken.
✗ Branch 42 not taken.
✗ Branch 43 not taken.
✓ Branch 44 taken 372 times.
✓ Branch 45 taken 216 times.
✓ Branch 46 taken 112 times.
✓ Branch 47 taken 100 times.
2052891 return (abs(a[0]-b[0]) > eps ? a[0] < b[0] : a[1] < b[1]);
622 });
623
624 1076660 auto removeIt = std::unique(points.begin(), points.end(), [&eps](const auto& a, const auto&b)
625 {
626 880236 return (b-a).two_norm() < eps;
627 });
628
629
2/2
✓ Branch 1 taken 78952 times.
✓ Branch 2 taken 117224 times.
196424 points.erase(removeIt, points.end());
630
631 // return false if we don't have at least three unique points
632
2/2
✓ Branch 0 taken 78952 times.
✓ Branch 1 taken 117224 times.
196424 if (points.size() < 3)
633 return false;
634
635 // intersection polygon is convex hull of above points
636
2/6
✗ Branch 1 not taken.
✓ Branch 2 taken 78952 times.
✗ Branch 3 not taken.
✓ Branch 4 taken 78952 times.
✗ Branch 5 not taken.
✗ Branch 6 not taken.
79188 intersection = grahamConvexHull<2>(points);
637
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 78952 times.
79188 assert(!intersection.empty());
638 return true;
639 392480 }
640
641 /*!
642 * \brief Colliding two polygons
643 * \param geo1/geo2 The geometries to intersect
644 * \param intersection Container to store the corners of intersection segment
645 * \note this overload is used when segment-like intersections are seeked
646 * \todo implement this query
647 */
648 template<class P = Policy, std::enable_if_t<P::dimIntersection == 1, int> = 0>
649 static bool intersection(const Geometry1& geo1, const Geometry2& geo2, Intersection& intersection)
650 {
651 static_assert(int(dimworld) == int(Geometry2::coorddimension), "Can only collide geometries of same coordinate dimension");
652 DUNE_THROW(Dune::NotImplemented, "Polygon-polygon intersection detection for segment-like intersections");
653 }
654
655 /*!
656 * \brief Colliding two polygons
657 * \param geo1/geo2 The geometries to intersect
658 * \param intersection The intersection point
659 * \note this overload is used when point-like intersections are seeked
660 * \todo implement this query
661 */
662 template<class P = Policy, std::enable_if_t<P::dimIntersection == 0, int> = 0>
663 static bool intersection(const Geometry1& geo1, const Geometry2& geo2, Intersection& intersection)
664 {
665 static_assert(int(dimworld) == int(Geometry2::coorddimension), "Can only collide geometries of same coordinate dimension");
666 DUNE_THROW(Dune::NotImplemented, "Polygon-polygon intersection detection for touching points");
667 }
668 };
669
670 /*!
671 * \ingroup Geometry
672 * \brief A class for polyhedron--segment intersection in 3d space
673 */
674 template <class Geometry1, class Geometry2, class Policy>
675 class GeometryIntersection<Geometry1, Geometry2, Policy, 3, 3, 1>
676 {
677 enum { dimworld = 3 };
678 enum { dim1 = 3 };
679 enum { dim2 = 1 };
680
681 public:
682 using ctype = typename Policy::ctype;
683 using Point = typename Policy::Point;
684 using Intersection = typename Policy::Intersection;
685
686 private:
687 static constexpr ctype eps_ = 1.5e-7; // base epsilon for floating point comparisons
688
689 public:
690 /*!
691 * \brief Colliding segment and convex polyhedron
692 * \note Algorithm based on the one from "Real-Time Collision Detection" by Christer Ericson,
693 * published by Morgan Kaufmann Publishers, (c) 2005 Elsevier Inc.
694 * Basis is the theorem that for any two non-intersecting convex polyhedrons
695 * a separating plane exists.
696 * \param geo1/geo2 The geometries to intersect
697 * \param intersection If the geometries collide intersection holds the corner points of
698 * the intersection object in global coordinates.
699 * \note This overload is used when segment-like intersections are seeked.
700 */
701 template<class P = Policy, std::enable_if_t<P::dimIntersection == 1, int> = 0>
702 346620 static bool intersection(const Geometry1& geo1, const Geometry2& geo2, Intersection& intersection)
703 {
704 static_assert(int(dimworld) == int(Geometry2::coorddimension), "Can only collide geometries of same coordinate dimension");
705
706 ctype tfirst, tlast;
707
2/2
✓ Branch 0 taken 49864 times.
✓ Branch 1 taken 150548 times.
346620 if (intersect_(geo1, geo2, tfirst, tlast))
708 {
709 // Intersection exists. Export the intersections geometry now:
710 // s(t) = a + t(b-a) in [tfirst, tlast]
711 66416 intersection = Intersection({geo2.global(tfirst), geo2.global(tlast)});
712 50408 return true;
713 }
714
715 return false;
716 }
717
718 /*!
719 * \brief Colliding segment and convex polyhedron
720 * \note Algorithm based on the one from "Real-Time Collision Detection" by Christer Ericson,
721 * published by Morgan Kaufmann Publishers, (c) 2005 Elsevier Inc.
722 * Basis is the theorem that for any two non-intersecting convex polyhedrons
723 * a separating plane exists.
724 * \param geo1/geo2 The geometries to intersect
725 * \param intersection If the geometries collide intersection holds the corner points of
726 * the intersection object in global coordinates.
727 * \note This overload is used when point-like intersections are seeked.
728 */
729 template<class P = Policy, std::enable_if_t<P::dimIntersection == 0, int> = 0>
730 static bool intersection(const Geometry1& geo1, const Geometry2& geo2, Intersection& intersection)
731 {
732 static_assert(int(dimworld) == int(Geometry2::coorddimension), "Can only collide geometries of same coordinate dimension");
733
734 ctype tfirst, tlast;
735 if (intersect_(geo1, geo2, tfirst, tlast))
736 {
737 // if start & end point are same, the intersection is a point
738 using std::abs;
739 if ( abs(tfirst - tlast) < eps_ )
740 {
741 intersection = Intersection(geo2.global(tfirst));
742 return true;
743 }
744 }
745
746 return false;
747 }
748
749 private:
750 /*!
751 * \brief Obtain local coordinates of start/end point of the intersecting segment.
752 */
753 200412 static bool intersect_(const Geometry1& geo1, const Geometry2& geo2, ctype& tfirst, ctype& tlast)
754 {
755 // lambda to obtain facet corners on geo1
756
16/49
✓ Branch 1 taken 180252 times.
✗ Branch 2 not taken.
✓ Branch 4 taken 180252 times.
✗ Branch 5 not taken.
✓ Branch 7 taken 180252 times.
✗ Branch 8 not taken.
✓ Branch 10 taken 180252 times.
✗ Branch 11 not taken.
✓ Branch 13 taken 180252 times.
✗ Branch 14 not taken.
✓ Branch 16 taken 9040 times.
✗ Branch 17 not taken.
✓ Branch 19 taken 9040 times.
✗ Branch 20 not taken.
✓ Branch 22 taken 9040 times.
✗ Branch 23 not taken.
✓ Branch 25 taken 9040 times.
✗ Branch 26 not taken.
✓ Branch 28 taken 6400 times.
✗ Branch 29 not taken.
✓ Branch 31 taken 6400 times.
✗ Branch 32 not taken.
✓ Branch 34 taken 6400 times.
✗ Branch 35 not taken.
✓ Branch 37 taken 6400 times.
✗ Branch 38 not taken.
✓ Branch 40 taken 4720 times.
✗ Branch 41 not taken.
✓ Branch 43 taken 4720 times.
✗ Branch 44 not taken.
✓ Branch 46 taken 4720 times.
✗ Branch 47 not taken.
✗ Branch 48 not taken.
✗ Branch 49 not taken.
✗ Branch 50 not taken.
✗ Branch 51 not taken.
✗ Branch 52 not taken.
✗ Branch 53 not taken.
✗ Branch 54 not taken.
✗ Branch 55 not taken.
✗ Branch 56 not taken.
✗ Branch 57 not taken.
✗ Branch 58 not taken.
✗ Branch 59 not taken.
✗ Branch 60 not taken.
✗ Branch 61 not taken.
✗ Branch 62 not taken.
✗ Branch 63 not taken.
✗ Branch 15 not taken.
693240 auto getFacetCorners = [] (const Geometry1& geo1)
757 {
758
3/6
✓ Branch 0 taken 4195 times.
✓ Branch 1 taken 157865 times.
✗ Branch 2 not taken.
✗ Branch 3 not taken.
✓ Branch 4 taken 2432 times.
✗ Branch 5 not taken.
200412 std::vector< std::vector<int> > facetCorners;
759 // sort facet corner so that normal n = (p1-p0)x(p2-p0) always points outwards
760
4/5
✓ Branch 0 taken 19955 times.
✓ Branch 1 taken 9040 times.
✓ Branch 2 taken 6400 times.
✓ Branch 3 taken 4720 times.
✗ Branch 4 not taken.
40115 switch (geo1.corners())
761 {
762 // todo compute intersection geometries
763
1/2
✓ Branch 1 taken 19955 times.
✗ Branch 2 not taken.
19955 case 8: // hexahedron
764
9/19
✓ Branch 1 taken 177820 times.
✗ Branch 2 not taken.
✓ Branch 4 taken 177820 times.
✗ Branch 5 not taken.
✓ Branch 6 taken 1066920 times.
✓ Branch 7 taken 177820 times.
✗ Branch 9 not taken.
✗ Branch 10 not taken.
✓ Branch 13 taken 2432 times.
✗ Branch 14 not taken.
✓ Branch 16 taken 2432 times.
✗ Branch 17 not taken.
✓ Branch 18 taken 14592 times.
✓ Branch 19 taken 2432 times.
✗ Branch 21 not taken.
✗ Branch 22 not taken.
✓ Branch 8 taken 94560 times.
✗ Branch 11 not taken.
✗ Branch 12 not taken.
1622268 facetCorners = {{2, 0, 6, 4}, {1, 3, 5, 7}, {0, 1, 4, 5},
765 {3, 2, 7, 6}, {1, 0, 3, 2}, {4, 5, 6, 7}};
766 19955 break;
767
1/2
✓ Branch 1 taken 9040 times.
✗ Branch 2 not taken.
9040 case 6: // prism
768
5/12
✓ Branch 1 taken 9040 times.
✗ Branch 2 not taken.
✓ Branch 4 taken 9040 times.
✗ Branch 5 not taken.
✓ Branch 6 taken 45200 times.
✓ Branch 7 taken 9040 times.
✓ Branch 8 taken 45200 times.
✗ Branch 9 not taken.
✗ Branch 10 not taken.
✗ Branch 11 not taken.
✗ Branch 12 not taken.
✗ Branch 13 not taken.
72320 facetCorners = {{0, 2, 1}, {3, 4, 5}, {0, 1, 3, 4}, {0, 3, 2, 5}, {1, 2, 4, 5}};
769 9040 break;
770
1/2
✓ Branch 1 taken 6400 times.
✗ Branch 2 not taken.
6400 case 5: // pyramid
771
5/12
✓ Branch 1 taken 6400 times.
✗ Branch 2 not taken.
✓ Branch 4 taken 6400 times.
✗ Branch 5 not taken.
✓ Branch 6 taken 32000 times.
✓ Branch 7 taken 6400 times.
✓ Branch 8 taken 32000 times.
✗ Branch 9 not taken.
✗ Branch 10 not taken.
✗ Branch 11 not taken.
✗ Branch 12 not taken.
✗ Branch 13 not taken.
51200 facetCorners = {{0, 2, 1, 3}, {0, 1, 4}, {1, 3, 4}, {2, 4, 3}, {0, 4, 2}};
772 6400 break;
773
1/2
✓ Branch 1 taken 4720 times.
✗ Branch 2 not taken.
4720 case 4: // tetrahedron
774
5/12
✓ Branch 1 taken 4720 times.
✗ Branch 2 not taken.
✓ Branch 4 taken 4720 times.
✗ Branch 5 not taken.
✓ Branch 6 taken 18880 times.
✓ Branch 7 taken 4720 times.
✓ Branch 8 taken 18880 times.
✗ Branch 9 not taken.
✗ Branch 10 not taken.
✗ Branch 11 not taken.
✗ Branch 12 not taken.
✗ Branch 13 not taken.
33040 facetCorners = {{1, 0, 2}, {0, 1, 3}, {0, 3, 2}, {1, 2, 3}};
775 4720 break;
776 default:
777
0/38
✗ Branch 1 not taken.
✗ Branch 2 not taken.
✗ Branch 4 not taken.
✗ Branch 5 not taken.
✗ Branch 7 not taken.
✗ Branch 8 not taken.
✗ Branch 10 not taken.
✗ Branch 11 not taken.
✗ Branch 13 not taken.
✗ Branch 14 not taken.
✗ Branch 16 not taken.
✗ Branch 17 not taken.
✗ Branch 19 not taken.
✗ Branch 20 not taken.
✗ Branch 22 not taken.
✗ Branch 23 not taken.
✗ Branch 25 not taken.
✗ Branch 26 not taken.
✗ Branch 28 not taken.
✗ Branch 29 not taken.
✗ Branch 31 not taken.
✗ Branch 32 not taken.
✗ Branch 34 not taken.
✗ Branch 35 not taken.
✗ Branch 37 not taken.
✗ Branch 38 not taken.
✗ Branch 40 not taken.
✗ Branch 41 not taken.
✗ Branch 43 not taken.
✗ Branch 44 not taken.
✗ Branch 46 not taken.
✗ Branch 47 not taken.
✗ Branch 30 not taken.
✗ Branch 33 not taken.
✗ Branch 36 not taken.
✗ Branch 39 not taken.
✗ Branch 42 not taken.
✗ Branch 45 not taken.
160297 DUNE_THROW(Dune::NotImplemented, "Collision of segment and geometry of type "
778 << geo1.type() << ", "<< geo1.corners() << " corners.");
779 }
780
781 200412 return facetCorners;
782 };
783
784 // lambda to obtain the normal on a facet
785 1538611 auto computeNormal = [&geo1] (const std::vector<int>& facetCorners)
786 {
787 2024767 const auto v0 = geo1.corner(facetCorners[1]) - geo1.corner(facetCorners[0]);
788 2024767 const auto v1 = geo1.corner(facetCorners[2]) - geo1.corner(facetCorners[0]);
789
790 816791 auto n = crossProduct(v0, v1);
791 816791 n /= n.two_norm();
792
793 816791 return n;
794 };
795
796 200412 return Detail::computeSegmentIntersection(geo1, geo2, eps_, tfirst, tlast, getFacetCorners, computeNormal);
797 }
798 };
799
800 /*!
801 * \ingroup Geometry
802 * \brief A class for segment--polyhedron intersection in 3d space
803 */
804 template <class Geometry1, class Geometry2, class Policy>
805 class GeometryIntersection<Geometry1, Geometry2, Policy, 3, 1, 3>
806 : public GeometryIntersection<Geometry2, Geometry1, Policy, 3, 3, 1>
807 {
808 using Base = GeometryIntersection<Geometry2, Geometry1, Policy, 3, 3, 1>;
809 public:
810 /*!
811 * \brief Colliding segment and convex polyhedron
812 * \param geo1/geo2 The geometries to intersect
813 * \param intersection If the geometries collide intersection holds the
814 * corner points of the intersection object in global coordinates.
815 * \note This forwards to the polyhedron-segment specialization with swapped arguments.
816 */
817 template<class P = Policy>
818 145753 static bool intersection(const Geometry1& geo1, const Geometry2& geo2, typename Base::Intersection& intersection)
819 {
820
1/2
✓ Branch 1 taken 143776 times.
✗ Branch 2 not taken.
145753 return Base::intersection(geo2, geo1, intersection);
821 }
822 };
823
824 /*!
825 * \ingroup Geometry
826 * \brief A class for polygon--polygon intersections in 3d space
827 */
828 template <class Geometry1, class Geometry2, class Policy>
829 class GeometryIntersection<Geometry1, Geometry2, Policy, 3, 2, 2>
830 {
831 enum { dimworld = 3 };
832 enum { dim1 = 2 };
833 enum { dim2 = 2 };
834
835 public:
836 using ctype = typename Policy::ctype;
837 using Point = typename Policy::Point;
838 using Intersection = typename Policy::Intersection;
839
840 private:
841 static constexpr ctype eps_ = 1.5e-7; // base epsilon for floating point comparisons
842
843 public:
844 /*!
845 * \brief Colliding two polygons
846 * \note First we find the vertex candidates for the intersection region as follows:
847 * Add vertices of first polygon that are inside the second polygon
848 * Add intersections of polygon edges
849 * Remove duplicate points from the list
850 * Compute the convex hull polygon
851 * \param geo1/geo2 The geometries to intersect
852 * \param intersection Container to store the corner points of the polygon (as convex hull)
853 * \note This overload is used when polygon like intersections are seeked
854 */
855 template<class P = Policy, std::enable_if_t<P::dimIntersection == 2, int> = 0>
856 49 static bool intersection(const Geometry1& geo1, const Geometry2& geo2, Intersection& intersection)
857 {
858 static_assert(int(dimworld) == int(Geometry2::coorddimension), "Can only collide geometries of same coordinate dimension");
859
860 // if the geometries are not parallel, there cannot be a polygon intersection
861 49 const auto a1 = geo1.corner(1) - geo1.corner(0);
862 49 const auto b1 = geo1.corner(2) - geo1.corner(0);
863 49 const auto n1 = crossProduct(a1, b1);
864
865 49 const auto a2 = geo2.corner(1) - geo2.corner(0);
866 49 const auto b2 = geo2.corner(2) - geo2.corner(0);
867 49 const auto n2 = crossProduct(a2, b2);
868
869 // compute an epsilon scaled with larger edge length
870 49 const auto a1Norm2 = a1.two_norm2();
871
2/2
✓ Branch 0 taken 48 times.
✓ Branch 1 taken 1 times.
49 const auto b1Norm2 = b1.two_norm2();
872
873 using std::max;
874 49 const auto maxNorm2 = max(a1Norm2, b1Norm2);
875 49 const auto eps2 = maxNorm2*eps_;
876
877 // early exit if polygons are not parallel
878 using std::abs;
879
2/2
✓ Branch 1 taken 2 times.
✓ Branch 2 taken 47 times.
98 if (crossProduct(n1, n2).two_norm2() > eps2*maxNorm2)
880 return false;
881
882 // they are parallel, verify that they are on the same plane
883 94 auto d1 = geo2.corner(0) - geo1.corner(0);
884
2/2
✓ Branch 0 taken 10 times.
✓ Branch 1 taken 37 times.
47 if (d1.two_norm2() < eps2)
885 20 d1 = geo2.corner(1) - geo1.corner(0);
886
887 using std::sqrt;
888 47 const auto maxNorm = sqrt(maxNorm2);
889 47 const auto eps3 = maxNorm*eps2;
890
891
2/2
✓ Branch 0 taken 4 times.
✓ Branch 1 taken 43 times.
47 if (abs(d1*n2) > eps3)
892 return false;
893
894 // the candidate intersection points
895
1/2
✓ Branch 1 taken 43 times.
✗ Branch 2 not taken.
43 std::vector<Point> points; points.reserve(8);
896
897 // add polygon1 corners that are inside polygon2
898
2/2
✓ Branch 1 taken 130 times.
✓ Branch 2 taken 43 times.
173 for (int i = 0; i < geo1.corners(); ++i)
899
3/4
✓ Branch 2 taken 130 times.
✗ Branch 3 not taken.
✓ Branch 4 taken 50 times.
✓ Branch 5 taken 80 times.
130 if (intersectsPointGeometry(geo1.corner(i), geo2))
900
1/2
✓ Branch 2 taken 50 times.
✗ Branch 3 not taken.
50 points.emplace_back(geo1.corner(i));
901
902
2/2
✓ Branch 0 taken 38 times.
✓ Branch 1 taken 5 times.
43 const auto numPoints1 = points.size();
903 43 const bool resultIsGeo1 = numPoints1 == geo1.corners();
904
2/2
✓ Branch 0 taken 38 times.
✓ Branch 1 taken 5 times.
43 if (!resultIsGeo1)
905 {
906 // add polygon2 corners that are inside polygon1
907
2/2
✓ Branch 1 taken 126 times.
✓ Branch 2 taken 38 times.
164 for (int i = 0; i < geo2.corners(); ++i)
908
3/4
✓ Branch 2 taken 126 times.
✗ Branch 3 not taken.
✓ Branch 4 taken 50 times.
✓ Branch 5 taken 76 times.
126 if (intersectsPointGeometry(geo2.corner(i), geo1))
909
1/2
✓ Branch 2 taken 50 times.
✗ Branch 3 not taken.
50 points.emplace_back(geo2.corner(i));
910
911
1/2
✓ Branch 0 taken 38 times.
✗ Branch 1 not taken.
38 const bool resultIsGeo2 = (points.size() - numPoints1) == geo2.corners();
912
1/2
✓ Branch 0 taken 38 times.
✗ Branch 1 not taken.
38 if (!resultIsGeo2)
913 {
914 38 const auto referenceElement1 = referenceElement(geo1);
915 38 const auto referenceElement2 = referenceElement(geo2);
916
917 // add intersections of edges
918 using SegGeometry = Dune::MultiLinearGeometry<ctype, 1, dimworld>;
919 using PointPolicy = IntersectionPolicy::PointPolicy<ctype, dimworld>;
920
2/2
✓ Branch 1 taken 114 times.
✓ Branch 2 taken 38 times.
152 for (int i = 0; i < referenceElement1.size(dim1-1); ++i)
921 {
922 114 const auto localEdgeGeom1 = referenceElement1.template geometry<dim1-1>(i);
923
1/2
✓ Branch 0 taken 114 times.
✗ Branch 1 not taken.
114 const auto edge1 = SegGeometry(
924 Dune::GeometryTypes::line,
925
1/2
✓ Branch 1 taken 114 times.
✗ Branch 2 not taken.
114 std::vector<Point>({
926 114 geo1.global(localEdgeGeom1.corner(0)),
927 114 geo1.global(localEdgeGeom1.corner(1))
928 })
929 );
930
931
2/2
✓ Branch 1 taken 378 times.
✓ Branch 2 taken 114 times.
492 for (int j = 0; j < referenceElement2.size(dim2-1); ++j)
932 {
933 378 const auto localEdgeGeom2 = referenceElement2.template geometry<dim2-1>(j);
934
1/2
✓ Branch 0 taken 378 times.
✗ Branch 1 not taken.
378 const auto edge2 = SegGeometry(
935 Dune::GeometryTypes::line,
936
1/4
✓ Branch 1 taken 378 times.
✗ Branch 2 not taken.
✗ Branch 3 not taken.
✗ Branch 4 not taken.
378 std::vector<Point>({
937 378 geo2.global(localEdgeGeom2.corner(0)),
938 378 geo2.global(localEdgeGeom2.corner(1))
939 })
940 );
941
942 using EdgeTest = GeometryIntersection<SegGeometry, SegGeometry, PointPolicy>;
943 378 typename EdgeTest::Intersection edgeIntersection;
944
2/2
✓ Branch 1 taken 154 times.
✓ Branch 2 taken 224 times.
378 if (EdgeTest::intersection(edge1, edge2, edgeIntersection))
945
1/2
✓ Branch 1 taken 154 times.
✗ Branch 2 not taken.
154 points.emplace_back(edgeIntersection);
946 }
947 }
948 }
949 }
950
951
1/2
✓ Branch 0 taken 43 times.
✗ Branch 1 not taken.
43 if (points.empty())
952 return false;
953
954 // remove duplicates
955 43 const auto eps = maxNorm*eps_;
956
4/24
✗ Branch 0 not taken.
✗ Branch 1 not taken.
✗ Branch 2 not taken.
✗ Branch 3 not taken.
✓ Branch 4 taken 60 times.
✓ Branch 5 taken 248 times.
✗ Branch 6 not taken.
✗ Branch 7 not taken.
✗ Branch 8 not taken.
✗ Branch 9 not taken.
✗ Branch 10 not taken.
✗ Branch 11 not taken.
✗ Branch 12 not taken.
✗ Branch 13 not taken.
✗ Branch 14 not taken.
✗ Branch 15 not taken.
✗ Branch 16 not taken.
✗ Branch 17 not taken.
✗ Branch 18 not taken.
✗ Branch 19 not taken.
✗ Branch 20 not taken.
✗ Branch 21 not taken.
✓ Branch 22 taken 71 times.
✓ Branch 23 taken 140 times.
562 std::sort(points.begin(), points.end(), [eps] (const auto& a, const auto& b) -> bool
957 {
958 using std::abs;
959
4/24
✗ Branch 0 not taken.
✗ Branch 1 not taken.
✗ Branch 2 not taken.
✗ Branch 3 not taken.
✓ Branch 4 taken 60 times.
✓ Branch 5 taken 248 times.
✗ Branch 6 not taken.
✗ Branch 7 not taken.
✗ Branch 8 not taken.
✗ Branch 9 not taken.
✗ Branch 10 not taken.
✗ Branch 11 not taken.
✗ Branch 12 not taken.
✗ Branch 13 not taken.
✗ Branch 14 not taken.
✗ Branch 15 not taken.
✗ Branch 16 not taken.
✗ Branch 17 not taken.
✗ Branch 18 not taken.
✗ Branch 19 not taken.
✗ Branch 20 not taken.
✗ Branch 21 not taken.
✓ Branch 22 taken 71 times.
✓ Branch 23 taken 140 times.
907 return (abs(a[0]-b[0]) > eps ? a[0] < b[0]
960
4/24
✗ Branch 0 not taken.
✗ Branch 1 not taken.
✗ Branch 2 not taken.
✗ Branch 3 not taken.
✓ Branch 4 taken 84 times.
✓ Branch 5 taken 164 times.
✗ Branch 6 not taken.
✗ Branch 7 not taken.
✗ Branch 8 not taken.
✗ Branch 9 not taken.
✗ Branch 10 not taken.
✗ Branch 11 not taken.
✗ Branch 12 not taken.
✗ Branch 13 not taken.
✗ Branch 14 not taken.
✗ Branch 15 not taken.
✗ Branch 16 not taken.
✗ Branch 17 not taken.
✗ Branch 18 not taken.
✗ Branch 19 not taken.
✗ Branch 20 not taken.
✗ Branch 21 not taken.
✓ Branch 22 taken 48 times.
✓ Branch 23 taken 92 times.
388 : (abs(a[1]-b[1]) > eps ? a[1] < b[1]
961 256 : (a[2] < b[2])));
962 });
963
964 43 const auto squaredEps = eps*eps;
965
2/2
✓ Branch 2 taken 21 times.
✓ Branch 3 taken 22 times.
43 points.erase(std::unique(
966 points.begin(), points.end(),
967 422 [squaredEps] (const auto& a, const auto&b) { return (b-a).two_norm2() < squaredEps; }),
968 43 points.end()
969 );
970
971 // return false if we don't have at least three unique points
972
2/2
✓ Branch 0 taken 21 times.
✓ Branch 1 taken 22 times.
43 if (points.size() < 3)
973 return false;
974
975 // intersection polygon is convex hull of above points
976
2/6
✗ Branch 1 not taken.
✓ Branch 2 taken 21 times.
✗ Branch 3 not taken.
✓ Branch 4 taken 21 times.
✗ Branch 5 not taken.
✗ Branch 6 not taken.
21 intersection = grahamConvexHull<2>(points);
977
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 21 times.
21 assert(!intersection.empty());
978 return true;
979 43 }
980
981 /*!
982 * \brief Colliding two polygons
983 * \param geo1/geo2 The geometries to intersect
984 * \param intersection Container to store the corners of intersection segment
985 * \note this overload is used when segment-like intersections are seeked
986 * \todo implement this query
987 */
988 template<class P = Policy, std::enable_if_t<P::dimIntersection == 1, int> = 0>
989 static bool intersection(const Geometry1& geo1, const Geometry2& geo2, Intersection& intersection)
990 {
991 static_assert(int(dimworld) == int(Geometry2::coorddimension), "Can only collide geometries of same coordinate dimension");
992 DUNE_THROW(Dune::NotImplemented, "Polygon-polygon intersection detection for segment-like intersections");
993 }
994
995 /*!
996 * \brief Colliding two polygons
997 * \param geo1/geo2 The geometries to intersect
998 * \param intersection The intersection point
999 * \note this overload is used when point-like intersections are seeked
1000 * \todo implement this query
1001 */
1002 template<class P = Policy, std::enable_if_t<P::dimIntersection == 0, int> = 0>
1003 static bool intersection(const Geometry1& geo1, const Geometry2& geo2, Intersection& intersection)
1004 {
1005 static_assert(int(dimworld) == int(Geometry2::coorddimension), "Can only collide geometries of same coordinate dimension");
1006 DUNE_THROW(Dune::NotImplemented, "Polygon-polygon intersection detection for touching points");
1007 }
1008 };
1009
1010 /*!
1011 * \ingroup Geometry
1012 * \brief A class for polyhedron--polygon intersection in 3d space
1013 */
1014 template <class Geometry1, class Geometry2, class Policy>
1015 class GeometryIntersection<Geometry1, Geometry2, Policy, 3, 3, 2>
1016 {
1017 enum { dimworld = 3 };
1018 enum { dim1 = 3 };
1019 enum { dim2 = 2 };
1020
1021 public:
1022 using ctype = typename Policy::ctype;
1023 using Point = typename Policy::Point;
1024 using Intersection = typename Policy::Intersection;
1025
1026 private:
1027 static constexpr ctype eps_ = 1.5e-7; // base epsilon for floating point comparisons
1028
1029 public:
1030 /*!
1031 * \brief Colliding polygon and convex polyhedron
1032 * \note First we find the vertex candidates for the intersection region as follows:
1033 * Add triangle vertices that are inside the tetrahedron
1034 * Add tetrahedron vertices that are inside the triangle
1035 * Add all intersection points of tetrahedron edges (codim 2) with the triangle (codim 0) (6*1 tests)
1036 * Add all intersection points of triangle edges (codim 1) with tetrahedron faces (codim 1) (3*4 tests)
1037 * Remove duplicate points from the list
1038 * Compute the convex hull polygon
1039 * Return a triangulation of that polygon as intersection
1040 * \param geo1/geo2 The geometries to intersect
1041 * \param intersection Container to store the corner points of the polygon (as convex hull)
1042 * \note This overload is used when polygon like intersections are seeked
1043 */
1044 template<class P = Policy, std::enable_if_t<P::dimIntersection == 2, int> = 0>
1045 42719 static bool intersection(const Geometry1& geo1, const Geometry2& geo2, Intersection& intersection)
1046 {
1047 static_assert(int(dimworld) == int(Geometry2::coorddimension), "Can only collide geometries of same coordinate dimension");
1048
1049 // the candidate intersection points
1050
1/2
✓ Branch 1 taken 35111 times.
✗ Branch 2 not taken.
42719 std::vector<Point> points; points.reserve(10);
1051
1052 // add 3d geometry corners that are inside the 2d geometry
1053
3/3
✓ Branch 0 taken 253136 times.
✓ Branch 1 taken 35251 times.
✓ Branch 2 taken 20 times.
356879 for (int i = 0; i < geo1.corners(); ++i)
1054
5/5
✓ Branch 2 taken 8616 times.
✓ Branch 3 taken 18918 times.
✓ Branch 4 taken 221370 times.
✓ Branch 5 taken 144 times.
✓ Branch 1 taken 244680 times.
314160 if (intersectsPointGeometry(geo1.corner(i), geo2))
1055
2/3
✓ Branch 1 taken 23326 times.
✓ Branch 2 taken 16 times.
✗ Branch 3 not taken.
34158 points.emplace_back(geo1.corner(i));
1056
1057 // add 2d geometry corners that are inside the 3d geometry
1058
3/3
✓ Branch 0 taken 6432 times.
✓ Branch 1 taken 102133 times.
✓ Branch 2 taken 33503 times.
172696 for (int i = 0; i < geo2.corners(); ++i)
1059
5/5
✓ Branch 2 taken 90579 times.
✓ Branch 3 taken 13348 times.
✓ Branch 4 taken 16 times.
✓ Branch 5 taken 60 times.
✓ Branch 1 taken 3030 times.
129977 if (intersectsPointGeometry(geo2.corner(i), geo1))
1060
2/3
✓ Branch 1 taken 3030 times.
✓ Branch 2 taken 8130 times.
✗ Branch 3 not taken.
11480 points.emplace_back(geo2.corner(i));
1061
1062 // get some geometry types
1063 using PolyhedronFaceGeometry = Dune::MultiLinearGeometry<ctype, 2, dimworld>;
1064 using SegGeometry = Dune::MultiLinearGeometry<ctype, 1, dimworld>;
1065
1066
1/2
✓ Branch 1 taken 23581 times.
✗ Branch 2 not taken.
42719 const auto refElement1 = referenceElement(geo1);
1067 42719 const auto refElement2 = referenceElement(geo2);
1068
1069 // intersection policy for point-like intersections (used later)
1070 using PointPolicy = IntersectionPolicy::PointPolicy<ctype, dimworld>;
1071
1072 // add intersection points of all polyhedron edges (codim dim-1) with the polygon
1073
2/2
✓ Branch 1 taken 379944 times.
✓ Branch 2 taken 35111 times.
513959 for (int i = 0; i < refElement1.size(dim1-1); ++i)
1074 {
1075 471240 const auto localEdgeGeom = refElement1.template geometry<dim1-1>(i);
1076 900852 const auto p = geo1.global(localEdgeGeom.corner(0));
1077 471240 const auto q = geo1.global(localEdgeGeom.corner(1));
1078
2/4
✓ Branch 1 taken 379944 times.
✗ Branch 2 not taken.
✓ Branch 3 taken 379944 times.
✗ Branch 4 not taken.
942480 const auto segGeo = SegGeometry(Dune::GeometryTypes::line, std::vector<Point>{p, q});
1079
1080 using PolySegTest = GeometryIntersection<Geometry2, SegGeometry, PointPolicy>;
1081 471240 typename PolySegTest::Intersection polySegIntersection;
1082
3/4
✓ Branch 1 taken 379944 times.
✗ Branch 2 not taken.
✓ Branch 3 taken 53193 times.
✓ Branch 4 taken 326751 times.
471240 if (PolySegTest::intersection(geo2, segGeo, polySegIntersection))
1083
1/2
✓ Branch 1 taken 53193 times.
✗ Branch 2 not taken.
67145 points.emplace_back(std::move(polySegIntersection));
1084 }
1085
1086 // add intersection points of all polygon faces (codim 1) with the polyhedron faces
1087
2/2
✓ Branch 1 taken 196870 times.
✓ Branch 2 taken 35111 times.
285237 for (int i = 0; i < refElement1.size(1); ++i)
1088 {
1089
1/2
✓ Branch 1 taken 196870 times.
✗ Branch 2 not taken.
288166 const auto faceGeo = [&]()
1090 {
1091 196870 const auto localFaceGeo = refElement1.template geometry<1>(i);
1092
5/8
✓ Branch 0 taken 124806 times.
✓ Branch 1 taken 27592 times.
✓ Branch 2 taken 1536 times.
✗ Branch 3 not taken.
✓ Branch 4 taken 26136 times.
✗ Branch 5 not taken.
✓ Branch 6 taken 16800 times.
✗ Branch 7 not taken.
196870 if (localFaceGeo.corners() == 4)
1093 {
1094 169278 const auto a = geo1.global(localFaceGeo.corner(0));
1095 169278 const auto b = geo1.global(localFaceGeo.corner(1));
1096 169278 const auto c = geo1.global(localFaceGeo.corner(2));
1097 169278 const auto d = geo1.global(localFaceGeo.corner(3));
1098
1099
12/24
✓ Branch 1 taken 124806 times.
✗ Branch 2 not taken.
✓ Branch 4 taken 124806 times.
✗ Branch 5 not taken.
✓ Branch 6 taken 124806 times.
✗ Branch 7 not taken.
✓ Branch 9 taken 1536 times.
✗ Branch 10 not taken.
✓ Branch 12 taken 1536 times.
✗ Branch 13 not taken.
✓ Branch 14 taken 1536 times.
✗ Branch 15 not taken.
✓ Branch 17 taken 26136 times.
✗ Branch 18 not taken.
✓ Branch 20 taken 26136 times.
✗ Branch 21 not taken.
✓ Branch 22 taken 26136 times.
✗ Branch 23 not taken.
✓ Branch 25 taken 16800 times.
✗ Branch 26 not taken.
✓ Branch 28 taken 16800 times.
✗ Branch 29 not taken.
✓ Branch 30 taken 16800 times.
✗ Branch 31 not taken.
507834 return PolyhedronFaceGeometry(Dune::GeometryTypes::cube(2), std::vector<Point>{a, b, c, d});
1100 }
1101 else
1102 {
1103 27592 const auto a = geo1.global(localFaceGeo.corner(0));
1104 27592 const auto b = geo1.global(localFaceGeo.corner(1));
1105 27592 const auto c = geo1.global(localFaceGeo.corner(2));
1106
1107
3/24
✓ Branch 1 taken 27592 times.
✗ Branch 2 not taken.
✓ Branch 4 taken 27592 times.
✗ Branch 5 not taken.
✓ Branch 6 taken 27592 times.
✗ Branch 7 not taken.
✗ Branch 9 not taken.
✗ Branch 10 not taken.
✗ Branch 12 not taken.
✗ Branch 13 not taken.
✗ Branch 14 not taken.
✗ Branch 15 not taken.
✗ Branch 17 not taken.
✗ Branch 18 not taken.
✗ Branch 20 not taken.
✗ Branch 21 not taken.
✗ Branch 22 not taken.
✗ Branch 23 not taken.
✗ Branch 25 not taken.
✗ Branch 26 not taken.
✗ Branch 28 not taken.
✗ Branch 29 not taken.
✗ Branch 30 not taken.
✗ Branch 31 not taken.
82776 return PolyhedronFaceGeometry(Dune::GeometryTypes::simplex(2), std::vector<Point>{a, b, c});
1108 }
1109 }();
1110
1111
2/2
✓ Branch 1 taken 600354 times.
✓ Branch 2 taken 196870 times.
980992 for (int j = 0; j < refElement2.size(1); ++j)
1112 {
1113 738474 const auto localEdgeGeom = refElement2.template geometry<1>(j);
1114 738474 const auto p = geo2.global(localEdgeGeom.corner(0));
1115 738474 const auto q = geo2.global(localEdgeGeom.corner(1));
1116
1117
2/6
✓ Branch 1 taken 600354 times.
✗ Branch 2 not taken.
✓ Branch 3 taken 600354 times.
✗ Branch 4 not taken.
✗ Branch 5 not taken.
✗ Branch 6 not taken.
1476948 const auto segGeo = SegGeometry(Dune::GeometryTypes::line, std::vector<Point>{p, q});
1118
1119 using PolySegTest = GeometryIntersection<PolyhedronFaceGeometry, SegGeometry, PointPolicy>;
1120 738474 typename PolySegTest::Intersection polySegIntersection;
1121
3/4
✓ Branch 1 taken 600354 times.
✗ Branch 2 not taken.
✓ Branch 3 taken 66202 times.
✓ Branch 4 taken 534152 times.
738474 if (PolySegTest::intersection(faceGeo, segGeo, polySegIntersection))
1122
1/2
✓ Branch 1 taken 66202 times.
✗ Branch 2 not taken.
71674 points.emplace_back(std::move(polySegIntersection));
1123 }
1124 }
1125
1126 // return if no intersection points were found
1127
2/2
✓ Branch 0 taken 20324 times.
✓ Branch 1 taken 14787 times.
42719 if (points.empty()) return false;
1128
1129 // remove duplicates
1130 66446 const auto eps = (geo1.corner(0) - geo1.corner(1)).two_norm()*eps_;
1131
69/192
✗ Branch 0 not taken.
✗ Branch 1 not taken.
✗ Branch 2 not taken.
✗ Branch 3 not taken.
✗ Branch 4 not taken.
✗ Branch 5 not taken.
✗ Branch 6 not taken.
✗ Branch 7 not taken.
✓ Branch 8 taken 74023 times.
✓ Branch 9 taken 131455 times.
✓ Branch 10 taken 18007 times.
✓ Branch 11 taken 113448 times.
✗ Branch 12 not taken.
✗ Branch 13 not taken.
✗ Branch 14 not taken.
✗ Branch 15 not taken.
✗ Branch 16 not taken.
✗ Branch 17 not taken.
✗ Branch 18 not taken.
✗ Branch 19 not taken.
✗ Branch 20 not taken.
✗ Branch 21 not taken.
✗ Branch 22 not taken.
✗ Branch 23 not taken.
✗ Branch 24 not taken.
✗ Branch 25 not taken.
✗ Branch 26 not taken.
✗ Branch 27 not taken.
✗ Branch 28 not taken.
✗ Branch 29 not taken.
✗ Branch 30 not taken.
✗ Branch 31 not taken.
✓ Branch 32 taken 368 times.
✓ Branch 33 taken 364 times.
✓ Branch 34 taken 364 times.
✗ Branch 35 not taken.
✗ Branch 36 not taken.
✗ Branch 37 not taken.
✗ Branch 38 not taken.
✗ Branch 39 not taken.
✗ Branch 40 not taken.
✗ Branch 41 not taken.
✗ Branch 42 not taken.
✗ Branch 43 not taken.
✓ Branch 44 taken 33178 times.
✓ Branch 45 taken 73723 times.
✓ Branch 46 taken 12784 times.
✓ Branch 47 taken 60939 times.
✗ Branch 48 not taken.
✗ Branch 49 not taken.
✗ Branch 50 not taken.
✗ Branch 51 not taken.
✗ Branch 52 not taken.
✗ Branch 53 not taken.
✗ Branch 54 not taken.
✗ Branch 55 not taken.
✗ Branch 56 not taken.
✗ Branch 57 not taken.
✗ Branch 58 not taken.
✗ Branch 59 not taken.
✗ Branch 60 not taken.
✗ Branch 61 not taken.
✗ Branch 62 not taken.
✗ Branch 63 not taken.
✗ Branch 64 not taken.
✗ Branch 65 not taken.
✗ Branch 66 not taken.
✗ Branch 67 not taken.
✓ Branch 68 taken 720 times.
✓ Branch 69 taken 1774 times.
✗ Branch 70 not taken.
✓ Branch 71 taken 1774 times.
✓ Branch 72 taken 78 times.
✓ Branch 73 taken 69 times.
✗ Branch 74 not taken.
✓ Branch 75 taken 69 times.
✓ Branch 76 taken 35 times.
✓ Branch 77 taken 23 times.
✗ Branch 78 not taken.
✓ Branch 79 taken 23 times.
✓ Branch 80 taken 1 times.
✓ Branch 81 taken 9 times.
✗ Branch 82 not taken.
✓ Branch 83 taken 9 times.
✓ Branch 84 taken 4 times.
✓ Branch 85 taken 4 times.
✗ Branch 86 not taken.
✓ Branch 87 taken 4 times.
✓ Branch 88 taken 4 times.
✓ Branch 89 taken 2 times.
✗ Branch 90 not taken.
✓ Branch 91 taken 2 times.
✓ Branch 92 taken 1 times.
✓ Branch 93 taken 1 times.
✗ Branch 94 not taken.
✓ Branch 95 taken 1 times.
✓ Branch 96 taken 1 times.
✗ Branch 97 not taken.
✗ Branch 98 not taken.
✗ Branch 99 not taken.
✗ Branch 100 not taken.
✗ Branch 101 not taken.
✗ Branch 102 not taken.
✗ Branch 103 not taken.
✓ Branch 104 taken 18140 times.
✓ Branch 105 taken 21376 times.
✓ Branch 106 taken 10304 times.
✓ Branch 107 taken 11072 times.
✗ Branch 108 not taken.
✗ Branch 109 not taken.
✗ Branch 110 not taken.
✗ Branch 111 not taken.
✗ Branch 112 not taken.
✗ Branch 113 not taken.
✗ Branch 114 not taken.
✗ Branch 115 not taken.
✗ Branch 116 not taken.
✗ Branch 117 not taken.
✗ Branch 118 not taken.
✗ Branch 119 not taken.
✗ Branch 120 not taken.
✗ Branch 121 not taken.
✗ Branch 122 not taken.
✗ Branch 123 not taken.
✗ Branch 124 not taken.
✗ Branch 125 not taken.
✗ Branch 126 not taken.
✗ Branch 127 not taken.
✗ Branch 128 not taken.
✗ Branch 129 not taken.
✗ Branch 130 not taken.
✗ Branch 131 not taken.
✗ Branch 132 not taken.
✗ Branch 133 not taken.
✗ Branch 134 not taken.
✗ Branch 135 not taken.
✗ Branch 136 not taken.
✗ Branch 137 not taken.
✗ Branch 138 not taken.
✗ Branch 139 not taken.
✓ Branch 140 taken 6399 times.
✓ Branch 141 taken 7477 times.
✓ Branch 142 taken 1861 times.
✓ Branch 143 taken 5616 times.
✓ Branch 144 taken 19 times.
✓ Branch 145 taken 32 times.
✓ Branch 146 taken 23 times.
✓ Branch 147 taken 9 times.
✓ Branch 148 taken 1 times.
✓ Branch 149 taken 28 times.
✓ Branch 150 taken 21 times.
✓ Branch 151 taken 7 times.
✗ Branch 152 not taken.
✓ Branch 153 taken 4 times.
✗ Branch 154 not taken.
✓ Branch 155 taken 4 times.
✗ Branch 156 not taken.
✗ Branch 157 not taken.
✗ Branch 158 not taken.
✗ Branch 159 not taken.
✗ Branch 160 not taken.
✗ Branch 161 not taken.
✗ Branch 162 not taken.
✗ Branch 163 not taken.
✗ Branch 164 not taken.
✓ Branch 165 taken 4 times.
✗ Branch 166 not taken.
✓ Branch 167 taken 4 times.
✗ Branch 168 not taken.
✓ Branch 169 taken 4 times.
✗ Branch 170 not taken.
✓ Branch 171 taken 4 times.
✗ Branch 172 not taken.
✗ Branch 173 not taken.
✗ Branch 174 not taken.
✗ Branch 175 not taken.
✓ Branch 176 taken 372 times.
✓ Branch 177 taken 216 times.
✓ Branch 178 taken 216 times.
✗ Branch 179 not taken.
✓ Branch 180 taken 206 times.
✓ Branch 181 taken 866 times.
✗ Branch 182 not taken.
✓ Branch 183 taken 866 times.
✓ Branch 184 taken 9500 times.
✓ Branch 185 taken 8172 times.
✓ Branch 186 taken 4756 times.
✓ Branch 187 taken 3416 times.
✓ Branch 188 taken 3035 times.
✓ Branch 189 taken 4261 times.
✓ Branch 190 taken 818 times.
✓ Branch 191 taken 3443 times.
403725 const auto notEqual = [eps] (auto a, auto b) { using std::abs; return abs(b-a) > eps; };
1132 107782 std::sort(points.begin(), points.end(), [notEqual](const auto& a, const auto& b) -> bool
1133 {
1134
40/96
✗ Branch 0 not taken.
✗ Branch 1 not taken.
✗ Branch 2 not taken.
✗ Branch 3 not taken.
✓ Branch 4 taken 74023 times.
✓ Branch 5 taken 131455 times.
✗ Branch 6 not taken.
✗ Branch 7 not taken.
✗ Branch 8 not taken.
✗ Branch 9 not taken.
✗ Branch 10 not taken.
✗ Branch 11 not taken.
✗ Branch 12 not taken.
✗ Branch 13 not taken.
✗ Branch 14 not taken.
✗ Branch 15 not taken.
✓ Branch 16 taken 368 times.
✓ Branch 17 taken 364 times.
✗ Branch 18 not taken.
✗ Branch 19 not taken.
✗ Branch 20 not taken.
✗ Branch 21 not taken.
✓ Branch 22 taken 33178 times.
✓ Branch 23 taken 73723 times.
✗ Branch 24 not taken.
✗ Branch 25 not taken.
✗ Branch 26 not taken.
✗ Branch 27 not taken.
✗ Branch 28 not taken.
✗ Branch 29 not taken.
✗ Branch 30 not taken.
✗ Branch 31 not taken.
✗ Branch 32 not taken.
✗ Branch 33 not taken.
✓ Branch 34 taken 720 times.
✓ Branch 35 taken 1774 times.
✓ Branch 36 taken 78 times.
✓ Branch 37 taken 69 times.
✓ Branch 38 taken 35 times.
✓ Branch 39 taken 23 times.
✓ Branch 40 taken 1 times.
✓ Branch 41 taken 9 times.
✓ Branch 42 taken 4 times.
✓ Branch 43 taken 4 times.
✓ Branch 44 taken 4 times.
✓ Branch 45 taken 2 times.
✓ Branch 46 taken 1 times.
✓ Branch 47 taken 1 times.
✓ Branch 48 taken 1 times.
✗ Branch 49 not taken.
✗ Branch 50 not taken.
✗ Branch 51 not taken.
✓ Branch 52 taken 18140 times.
✓ Branch 53 taken 21376 times.
✗ Branch 54 not taken.
✗ Branch 55 not taken.
✗ Branch 56 not taken.
✗ Branch 57 not taken.
✗ Branch 58 not taken.
✗ Branch 59 not taken.
✗ Branch 60 not taken.
✗ Branch 61 not taken.
✗ Branch 62 not taken.
✗ Branch 63 not taken.
✗ Branch 64 not taken.
✗ Branch 65 not taken.
✗ Branch 66 not taken.
✗ Branch 67 not taken.
✗ Branch 68 not taken.
✗ Branch 69 not taken.
✓ Branch 70 taken 6399 times.
✓ Branch 71 taken 7477 times.
✓ Branch 72 taken 19 times.
✓ Branch 73 taken 32 times.
✓ Branch 74 taken 1 times.
✓ Branch 75 taken 28 times.
✗ Branch 76 not taken.
✓ Branch 77 taken 4 times.
✗ Branch 78 not taken.
✗ Branch 79 not taken.
✗ Branch 80 not taken.
✗ Branch 81 not taken.
✗ Branch 82 not taken.
✓ Branch 83 taken 4 times.
✗ Branch 84 not taken.
✓ Branch 85 taken 4 times.
✗ Branch 86 not taken.
✗ Branch 87 not taken.
✓ Branch 88 taken 372 times.
✓ Branch 89 taken 216 times.
✓ Branch 90 taken 206 times.
✓ Branch 91 taken 866 times.
✓ Branch 92 taken 9500 times.
✓ Branch 93 taken 8172 times.
✓ Branch 94 taken 3035 times.
✓ Branch 95 taken 4261 times.
645813 return (notEqual(a[0], b[0]) ? a[0] < b[0]
1135
29/96
✗ Branch 0 not taken.
✗ Branch 1 not taken.
✗ Branch 2 not taken.
✗ Branch 3 not taken.
✓ Branch 4 taken 18007 times.
✓ Branch 5 taken 113448 times.
✗ Branch 6 not taken.
✗ Branch 7 not taken.
✗ Branch 8 not taken.
✗ Branch 9 not taken.
✗ Branch 10 not taken.
✗ Branch 11 not taken.
✗ Branch 12 not taken.
✗ Branch 13 not taken.
✗ Branch 14 not taken.
✗ Branch 15 not taken.
✓ Branch 16 taken 364 times.
✗ Branch 17 not taken.
✗ Branch 18 not taken.
✗ Branch 19 not taken.
✗ Branch 20 not taken.
✗ Branch 21 not taken.
✓ Branch 22 taken 12784 times.
✓ Branch 23 taken 60939 times.
✗ Branch 24 not taken.
✗ Branch 25 not taken.
✗ Branch 26 not taken.
✗ Branch 27 not taken.
✗ Branch 28 not taken.
✗ Branch 29 not taken.
✗ Branch 30 not taken.
✗ Branch 31 not taken.
✗ Branch 32 not taken.
✗ Branch 33 not taken.
✗ Branch 34 not taken.
✓ Branch 35 taken 1774 times.
✗ Branch 36 not taken.
✓ Branch 37 taken 69 times.
✗ Branch 38 not taken.
✓ Branch 39 taken 23 times.
✗ Branch 40 not taken.
✓ Branch 41 taken 9 times.
✗ Branch 42 not taken.
✓ Branch 43 taken 4 times.
✗ Branch 44 not taken.
✓ Branch 45 taken 2 times.
✗ Branch 46 not taken.
✓ Branch 47 taken 1 times.
✗ Branch 48 not taken.
✗ Branch 49 not taken.
✗ Branch 50 not taken.
✗ Branch 51 not taken.
✓ Branch 52 taken 10304 times.
✓ Branch 53 taken 11072 times.
✗ Branch 54 not taken.
✗ Branch 55 not taken.
✗ Branch 56 not taken.
✗ Branch 57 not taken.
✗ Branch 58 not taken.
✗ Branch 59 not taken.
✗ Branch 60 not taken.
✗ Branch 61 not taken.
✗ Branch 62 not taken.
✗ Branch 63 not taken.
✗ Branch 64 not taken.
✗ Branch 65 not taken.
✗ Branch 66 not taken.
✗ Branch 67 not taken.
✗ Branch 68 not taken.
✗ Branch 69 not taken.
✓ Branch 70 taken 1861 times.
✓ Branch 71 taken 5616 times.
✓ Branch 72 taken 23 times.
✓ Branch 73 taken 9 times.
✓ Branch 74 taken 21 times.
✓ Branch 75 taken 7 times.
✗ Branch 76 not taken.
✓ Branch 77 taken 4 times.
✗ Branch 78 not taken.
✗ Branch 79 not taken.
✗ Branch 80 not taken.
✗ Branch 81 not taken.
✗ Branch 82 not taken.
✓ Branch 83 taken 4 times.
✗ Branch 84 not taken.
✓ Branch 85 taken 4 times.
✗ Branch 86 not taken.
✗ Branch 87 not taken.
✓ Branch 88 taken 216 times.
✗ Branch 89 not taken.
✗ Branch 90 not taken.
✓ Branch 91 taken 866 times.
✓ Branch 92 taken 4756 times.
✓ Branch 93 taken 3416 times.
✓ Branch 94 taken 818 times.
✓ Branch 95 taken 3443 times.
249864 : (notEqual(a[1], b[1]) ? a[1] < b[1]
1136 200710 : (a[2] < b[2])));
1137 });
1138
1139 24212 const auto squaredEps = eps*eps;
1140
2/2
✓ Branch 2 taken 13496 times.
✓ Branch 3 taken 6828 times.
24212 points.erase(std::unique(
1141 points.begin(), points.end(),
1142 267146 [squaredEps] (const auto& a, const auto&b) { return (b-a).two_norm2() < squaredEps; }),
1143 24212 points.end()
1144 );
1145
1146 // return false if we don't have more than three unique points
1147
2/2
✓ Branch 0 taken 13496 times.
✓ Branch 1 taken 6828 times.
24212 if (points.size() < 3) return false;
1148
1149 // intersection polygon is convex hull of above points
1150
2/6
✗ Branch 1 not taken.
✓ Branch 2 taken 13496 times.
✗ Branch 3 not taken.
✓ Branch 4 taken 13496 times.
✗ Branch 5 not taken.
✗ Branch 6 not taken.
16412 intersection = grahamConvexHull<2>(points);
1151
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 13496 times.
16412 assert(!intersection.empty());
1152
1153 return true;
1154 42719 }
1155
1156 /*!
1157 * \brief Colliding segment and convex polyhedron
1158 * \note First we find the vertex candidates for the intersection region as follows:
1159 * Add triangle vertices that are inside the tetrahedron
1160 * Add tetrahedron vertices that are inside the triangle
1161 * Add all intersection points of tetrahedron edges (codim 2) with the triangle (codim 0) (6*1 tests)
1162 * Add all intersection points of triangle edges (codim 1) with tetrahedron faces (codim 1) (3*4 tests)
1163 * Remove duplicate points from the list
1164 * Compute the convex hull polygon
1165 * Return a triangulation of that polygon as intersection
1166 * \param geo1/geo2 The geometries to intersect
1167 * \param intersection Container to store the intersection result
1168 * \todo implement overloads for segment or point-like intersections
1169 */
1170 template<class P = Policy, std::enable_if_t<P::dimIntersection != 2, int> = 0>
1171 static bool intersection(const Geometry1& geo1, const Geometry2& geo2, Intersection& intersection)
1172 {
1173 static_assert(int(dimworld) == int(Geometry2::coorddimension), "Can only collide geometries of same coordinate dimension");
1174 DUNE_THROW(Dune::NotImplemented, "Polyhedron-polygon intersection detection only implemented for polygon-like intersections");
1175 }
1176 };
1177
1178 /*!
1179 * \ingroup Geometry
1180 * \brief A class for polygon--polyhedron intersection in 3d space
1181 */
1182 template <class Geometry1, class Geometry2, class Policy>
1183 class GeometryIntersection<Geometry1, Geometry2, Policy, 3, 2, 3>
1184 : public GeometryIntersection<Geometry2, Geometry1, Policy, 3, 3, 2>
1185 {
1186 using Base = GeometryIntersection<Geometry2, Geometry1, Policy, 3, 3, 2>;
1187 public:
1188 /*!
1189 * \brief Colliding polygon and convex polyhedron
1190 * \param geo1/geo2 The geometries to intersect
1191 * \param intersection If the geometries collide intersection holds the
1192 * corner points of the intersection object in global coordinates.
1193 * \note This forwards to the polyhedron-polygon specialization with swapped arguments.
1194 */
1195 template<class P = Policy>
1196 4808 static bool intersection(const Geometry1& geo1, const Geometry2& geo2, typename Base::Intersection& intersection)
1197 {
1198
3/6
✓ Branch 1 taken 196 times.
✗ Branch 2 not taken.
✓ Branch 4 taken 256 times.
✗ Branch 5 not taken.
✓ Branch 7 taken 4356 times.
✗ Branch 8 not taken.
4808 return Base::intersection(geo2, geo1, intersection);
1199 }
1200 };
1201
1202 /*!
1203 * \ingroup Geometry
1204 * \brief A class for polyhedron--polyhedron intersection in 3d space
1205 */
1206 template <class Geometry1, class Geometry2, class Policy>
1207 class GeometryIntersection<Geometry1, Geometry2, Policy, 3, 3, 3>
1208 {
1209 enum { dimworld = 3 };
1210 enum { dim1 = 3 };
1211 enum { dim2 = 3 };
1212
1213 public:
1214 using ctype = typename Policy::ctype;
1215 using Point = typename Policy::Point;
1216 using Intersection = typename Policy::Intersection;
1217
1218 private:
1219 static constexpr ctype eps_ = 1.5e-7; // base epsilon for floating point comparisons
1220
1221 public:
1222 /*!
1223 * \brief Colliding two convex polyhedra
1224 * \note First we find the vertex candidates for the intersection region as follows:
1225 * Add vertices that are inside the other geometry for both geometries
1226 * Add all intersection points of edges (codim 2) with the other tetrahedron's faces triangle
1227 * Remove duplicate points from the list
1228 * Return a triangulation of the polyhedron formed by the convex hull of the point cloud
1229 * \param geo1/geo2 The geometries to intersect
1230 * \param intersection Container to store the corner points of the polygon (as convex hull)
1231 * \note This overload is used when polyhedron-like intersections are seeked
1232 */
1233 template<class P = Policy, std::enable_if_t<P::dimIntersection == 3, int> = 0>
1234 14668 static bool intersection(const Geometry1& geo1, const Geometry2& geo2, Intersection& intersection)
1235 {
1236 static_assert(
1237 int(dimworld) == int(Geometry2::coorddimension),
1238 "Can only collide geometries of same coordinate dimension"
1239 );
1240
1241 14668 const auto refElement1 = referenceElement(geo1);
1242 14668 const auto refElement2 = referenceElement(geo2);
1243
1244 // the candidate intersection points
1245 14668 std::vector<Point> points;
1246
1/2
✓ Branch 2 taken 8339 times.
✗ Branch 3 not taken.
14668 points.reserve(refElement1.size(2) + refElement2.size(2));
1247
1248 // add corners inside the other geometry
1249 55568 const auto addPointIntersections = [&](const auto& g1, const auto& g2)
1250 {
1251
6/6
✓ Branch 0 taken 18552 times.
✓ Branch 1 taken 4303 times.
✓ Branch 2 taken 1980 times.
✓ Branch 3 taken 15521 times.
✓ Branch 4 taken 96222 times.
✓ Branch 5 taken 11792 times.
148370 for (int i = 0; i < g1.corners(); ++i)
1252
8/8
✓ Branch 1 taken 15194 times.
✓ Branch 2 taken 4010 times.
✓ Branch 4 taken 762 times.
✓ Branch 5 taken 986 times.
✓ Branch 7 taken 28008 times.
✓ Branch 8 taken 66328 times.
✓ Branch 6 taken 15072 times.
✓ Branch 3 taken 1332 times.
131692 if (const auto& c = g1.corner(i); intersectsPointGeometry(c, g2))
1253 44632 points.emplace_back(c);
1254 };
1255
1256
1/2
✓ Branch 1 taken 8339 times.
✗ Branch 2 not taken.
14668 addPointIntersections(geo1, geo2);
1257
1/2
✓ Branch 1 taken 8339 times.
✗ Branch 2 not taken.
14668 addPointIntersections(geo2, geo1);
1258
1259 // get geometry types for the facets
1260 using PolyhedronFaceGeometry = Dune::MultiLinearGeometry<ctype, 2, dimworld>;
1261 using SegGeometry = Dune::MultiLinearGeometry<ctype, 1, dimworld>;
1262
1263 // intersection policy for point-like intersections (used later)
1264 using PointPolicy = IntersectionPolicy::PointPolicy<ctype, dimworld>;
1265
1266 // add intersection points of all edges with the faces of the other polyhedron
1267 34994 const auto addEdgeIntersections = [&](const auto& g1, const auto& g2, const auto& ref1, const auto& ref2)
1268 {
1269
6/6
✓ Branch 1 taken 15402 times.
✓ Branch 2 taken 2567 times.
✓ Branch 4 taken 13048 times.
✓ Branch 5 taken 2319 times.
✓ Branch 7 taken 70752 times.
✓ Branch 8 taken 11792 times.
115880 for (int i = 0; i < ref1.size(1); ++i)
1270 {
1271 219548 const auto faceGeo = [&]()
1272 {
1273 99202 const auto localFaceGeo = ref1.template geometry<1>(i);
1274
4/6
✓ Branch 0 taken 15402 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 11316 times.
✓ Branch 3 taken 1732 times.
✓ Branch 4 taken 70752 times.
✗ Branch 5 not taken.
99202 if (localFaceGeo.corners() == 4)
1275 {
1276 97470 const auto a = g1.global(localFaceGeo.corner(0));
1277 97470 const auto b = g1.global(localFaceGeo.corner(1));
1278 97470 const auto c = g1.global(localFaceGeo.corner(2));
1279 97470 const auto d = g1.global(localFaceGeo.corner(3));
1280
1281
3/6
✓ Branch 1 taken 15402 times.
✗ Branch 2 not taken.
✓ Branch 4 taken 11316 times.
✗ Branch 5 not taken.
✓ Branch 7 taken 70752 times.
✗ Branch 8 not taken.
194940 return PolyhedronFaceGeometry(
1282 Dune::GeometryTypes::cube(2), std::vector<Point>{a, b, c, d}
1283
6/12
✓ Branch 1 taken 15402 times.
✗ Branch 2 not taken.
✓ Branch 3 taken 15402 times.
✗ Branch 4 not taken.
✓ Branch 6 taken 11316 times.
✗ Branch 7 not taken.
✓ Branch 8 taken 11316 times.
✗ Branch 9 not taken.
✓ Branch 11 taken 70752 times.
✗ Branch 12 not taken.
✓ Branch 13 taken 70752 times.
✗ Branch 14 not taken.
194940 );
1284 }
1285 else
1286 {
1287 1732 const auto a = g1.global(localFaceGeo.corner(0));
1288 1732 const auto b = g1.global(localFaceGeo.corner(1));
1289 1732 const auto c = g1.global(localFaceGeo.corner(2));
1290
1291
1/6
✗ Branch 1 not taken.
✗ Branch 2 not taken.
✓ Branch 4 taken 1732 times.
✗ Branch 5 not taken.
✗ Branch 7 not taken.
✗ Branch 8 not taken.
3464 return PolyhedronFaceGeometry(
1292 Dune::GeometryTypes::simplex(2), std::vector<Point>{a, b, c}
1293
2/12
✗ Branch 1 not taken.
✗ Branch 2 not taken.
✗ Branch 3 not taken.
✗ Branch 4 not taken.
✓ Branch 6 taken 1732 times.
✗ Branch 7 not taken.
✓ Branch 8 taken 1732 times.
✗ Branch 9 not taken.
✗ Branch 11 not taken.
✗ Branch 12 not taken.
✗ Branch 13 not taken.
✗ Branch 14 not taken.
3464 );
1294 }
1295 }();
1296
1297
6/6
✓ Branch 1 taken 169236 times.
✓ Branch 2 taken 15402 times.
✓ Branch 4 taken 156576 times.
✓ Branch 5 taken 13048 times.
✓ Branch 7 taken 849024 times.
✓ Branch 8 taken 70752 times.
1274038 for (int j = 0; j < ref2.size(2); ++j)
1298 {
1299 1174836 const auto localEdgeGeom = ref2.template geometry<2>(j);
1300 2180436 const auto p = g2.global(localEdgeGeom.corner(0));
1301 1174836 const auto q = g2.global(localEdgeGeom.corner(1));
1302
1303
6/18
✓ Branch 1 taken 169236 times.
✗ Branch 2 not taken.
✓ Branch 3 taken 169236 times.
✗ Branch 4 not taken.
✗ Branch 5 not taken.
✗ Branch 6 not taken.
✓ Branch 8 taken 156576 times.
✗ Branch 9 not taken.
✓ Branch 10 taken 156576 times.
✗ Branch 11 not taken.
✗ Branch 12 not taken.
✗ Branch 13 not taken.
✓ Branch 15 taken 849024 times.
✗ Branch 16 not taken.
✓ Branch 17 taken 849024 times.
✗ Branch 18 not taken.
✗ Branch 19 not taken.
✗ Branch 20 not taken.
2349672 const auto segGeo = SegGeometry(Dune::GeometryTypes::line, std::vector<Point>{p, q});
1304
1305 using PolySegTest = GeometryIntersection<PolyhedronFaceGeometry, SegGeometry, PointPolicy>;
1306 1174836 typename PolySegTest::Intersection polySegIntersection;
1307
9/12
✓ Branch 1 taken 169236 times.
✗ Branch 2 not taken.
✓ Branch 3 taken 6421 times.
✓ Branch 4 taken 162815 times.
✓ Branch 6 taken 156576 times.
✗ Branch 7 not taken.
✓ Branch 8 taken 7442 times.
✓ Branch 9 taken 149134 times.
✓ Branch 11 taken 849024 times.
✗ Branch 12 not taken.
✓ Branch 13 taken 109584 times.
✓ Branch 14 taken 739440 times.
1174836 if (PolySegTest::intersection(faceGeo, segGeo, polySegIntersection))
1308
3/6
✓ Branch 1 taken 6421 times.
✗ Branch 2 not taken.
✓ Branch 4 taken 7442 times.
✗ Branch 5 not taken.
✓ Branch 7 taken 109584 times.
✗ Branch 8 not taken.
123447 points.emplace_back(std::move(polySegIntersection));
1309 }
1310 }
1311 };
1312
1313
1/2
✓ Branch 1 taken 8339 times.
✗ Branch 2 not taken.
14668 addEdgeIntersections(geo1, geo2, refElement1, refElement2);
1314
1/2
✓ Branch 1 taken 8339 times.
✗ Branch 2 not taken.
14668 addEdgeIntersections(geo2, geo1, refElement2, refElement1);
1315
1316 // return if no intersection points were found
1317
2/2
✓ Branch 0 taken 46 times.
✓ Branch 1 taken 8293 times.
14668 if (points.empty())
1318 return false;
1319
1320 // remove duplicates
1321 40944 const auto norm = (geo1.corner(0) - geo1.corner(1)).two_norm();
1322 14576 const auto eps = norm*eps_;
1323
79/96
✗ Branch 0 not taken.
✗ Branch 1 not taken.
✗ Branch 2 not taken.
✗ Branch 3 not taken.
✗ Branch 4 not taken.
✗ Branch 5 not taken.
✗ Branch 6 not taken.
✗ Branch 7 not taken.
✓ Branch 8 taken 25784 times.
✓ Branch 9 taken 41571 times.
✓ Branch 10 taken 17208 times.
✓ Branch 11 taken 24363 times.
✓ Branch 12 taken 3395 times.
✓ Branch 13 taken 4965 times.
✓ Branch 14 taken 1994 times.
✓ Branch 15 taken 2971 times.
✓ Branch 16 taken 4989 times.
✓ Branch 17 taken 10435 times.
✓ Branch 18 taken 2902 times.
✓ Branch 19 taken 7533 times.
✓ Branch 20 taken 322 times.
✓ Branch 21 taken 1365 times.
✓ Branch 22 taken 238 times.
✓ Branch 23 taken 1127 times.
✓ Branch 24 taken 132 times.
✓ Branch 25 taken 1249 times.
✓ Branch 26 taken 93 times.
✓ Branch 27 taken 1156 times.
✓ Branch 28 taken 29 times.
✓ Branch 29 taken 196 times.
✓ Branch 30 taken 61 times.
✓ Branch 31 taken 135 times.
✓ Branch 32 taken 153 times.
✓ Branch 33 taken 207 times.
✓ Branch 34 taken 64 times.
✓ Branch 35 taken 143 times.
✓ Branch 36 taken 24 times.
✓ Branch 37 taken 220 times.
✓ Branch 38 taken 44 times.
✓ Branch 39 taken 176 times.
✓ Branch 40 taken 16 times.
✓ Branch 41 taken 80 times.
✓ Branch 42 taken 4 times.
✓ Branch 43 taken 76 times.
✓ Branch 44 taken 10657 times.
✓ Branch 45 taken 10347 times.
✓ Branch 46 taken 5680 times.
✓ Branch 47 taken 4667 times.
✗ Branch 48 not taken.
✗ Branch 49 not taken.
✗ Branch 50 not taken.
✗ Branch 51 not taken.
✓ Branch 52 taken 73198 times.
✓ Branch 53 taken 224692 times.
✓ Branch 54 taken 60960 times.
✓ Branch 55 taken 163732 times.
✓ Branch 56 taken 20280 times.
✓ Branch 57 taken 69291 times.
✓ Branch 58 taken 16279 times.
✓ Branch 59 taken 53012 times.
✓ Branch 60 taken 30500 times.
✓ Branch 61 taken 71604 times.
✓ Branch 62 taken 13436 times.
✓ Branch 63 taken 58168 times.
✓ Branch 64 taken 3065 times.
✓ Branch 65 taken 5142 times.
✓ Branch 66 taken 2140 times.
✓ Branch 67 taken 3002 times.
✓ Branch 68 taken 1745 times.
✓ Branch 69 taken 4305 times.
✓ Branch 70 taken 520 times.
✓ Branch 71 taken 3785 times.
✓ Branch 72 taken 1570 times.
✓ Branch 73 taken 3730 times.
✓ Branch 74 taken 1442 times.
✓ Branch 75 taken 2288 times.
✓ Branch 76 taken 625 times.
✓ Branch 77 taken 1532 times.
✓ Branch 78 taken 125 times.
✓ Branch 79 taken 1407 times.
✓ Branch 80 taken 125 times.
✓ Branch 81 taken 637 times.
✗ Branch 82 not taken.
✓ Branch 83 taken 637 times.
✗ Branch 84 not taken.
✗ Branch 85 not taken.
✗ Branch 86 not taken.
✗ Branch 87 not taken.
✓ Branch 88 taken 1398 times.
✓ Branch 89 taken 2111 times.
✓ Branch 90 taken 406 times.
✓ Branch 91 taken 1705 times.
✓ Branch 92 taken 18369 times.
✓ Branch 93 taken 69559 times.
✓ Branch 94 taken 17014 times.
✓ Branch 95 taken 52545 times.
732180 const auto notEqual = [eps] (auto a, auto b) { using std::abs; return abs(b-a) > eps; };
1324 629196 std::sort(points.begin(), points.end(), [notEqual](const auto& a, const auto& b) -> bool
1325 {
1326
40/48
✗ Branch 0 not taken.
✗ Branch 1 not taken.
✗ Branch 2 not taken.
✗ Branch 3 not taken.
✓ Branch 4 taken 25784 times.
✓ Branch 5 taken 41571 times.
✓ Branch 6 taken 3395 times.
✓ Branch 7 taken 4965 times.
✓ Branch 8 taken 4989 times.
✓ Branch 9 taken 10435 times.
✓ Branch 10 taken 322 times.
✓ Branch 11 taken 1365 times.
✓ Branch 12 taken 132 times.
✓ Branch 13 taken 1249 times.
✓ Branch 14 taken 29 times.
✓ Branch 15 taken 196 times.
✓ Branch 16 taken 153 times.
✓ Branch 17 taken 207 times.
✓ Branch 18 taken 24 times.
✓ Branch 19 taken 220 times.
✓ Branch 20 taken 16 times.
✓ Branch 21 taken 80 times.
✓ Branch 22 taken 10657 times.
✓ Branch 23 taken 10347 times.
✗ Branch 24 not taken.
✗ Branch 25 not taken.
✓ Branch 26 taken 73198 times.
✓ Branch 27 taken 224692 times.
✓ Branch 28 taken 20280 times.
✓ Branch 29 taken 69291 times.
✓ Branch 30 taken 30500 times.
✓ Branch 31 taken 71604 times.
✓ Branch 32 taken 3065 times.
✓ Branch 33 taken 5142 times.
✓ Branch 34 taken 1745 times.
✓ Branch 35 taken 4305 times.
✓ Branch 36 taken 1570 times.
✓ Branch 37 taken 3730 times.
✓ Branch 38 taken 625 times.
✓ Branch 39 taken 1532 times.
✓ Branch 40 taken 125 times.
✓ Branch 41 taken 637 times.
✗ Branch 42 not taken.
✗ Branch 43 not taken.
✓ Branch 44 taken 1398 times.
✓ Branch 45 taken 2111 times.
✓ Branch 46 taken 18369 times.
✓ Branch 47 taken 69559 times.
1242852 return (notEqual(a[0], b[0]) ? a[0] < b[0]
1327
39/48
✗ Branch 0 not taken.
✗ Branch 1 not taken.
✗ Branch 2 not taken.
✗ Branch 3 not taken.
✓ Branch 4 taken 17208 times.
✓ Branch 5 taken 24363 times.
✓ Branch 6 taken 1994 times.
✓ Branch 7 taken 2971 times.
✓ Branch 8 taken 2902 times.
✓ Branch 9 taken 7533 times.
✓ Branch 10 taken 238 times.
✓ Branch 11 taken 1127 times.
✓ Branch 12 taken 93 times.
✓ Branch 13 taken 1156 times.
✓ Branch 14 taken 61 times.
✓ Branch 15 taken 135 times.
✓ Branch 16 taken 64 times.
✓ Branch 17 taken 143 times.
✓ Branch 18 taken 44 times.
✓ Branch 19 taken 176 times.
✓ Branch 20 taken 4 times.
✓ Branch 21 taken 76 times.
✓ Branch 22 taken 5680 times.
✓ Branch 23 taken 4667 times.
✗ Branch 24 not taken.
✗ Branch 25 not taken.
✓ Branch 26 taken 60960 times.
✓ Branch 27 taken 163732 times.
✓ Branch 28 taken 16279 times.
✓ Branch 29 taken 53012 times.
✓ Branch 30 taken 13436 times.
✓ Branch 31 taken 58168 times.
✓ Branch 32 taken 2140 times.
✓ Branch 33 taken 3002 times.
✓ Branch 34 taken 520 times.
✓ Branch 35 taken 3785 times.
✓ Branch 36 taken 1442 times.
✓ Branch 37 taken 2288 times.
✓ Branch 38 taken 125 times.
✓ Branch 39 taken 1407 times.
✗ Branch 40 not taken.
✓ Branch 41 taken 637 times.
✗ Branch 42 not taken.
✗ Branch 43 not taken.
✓ Branch 44 taken 406 times.
✓ Branch 45 taken 1705 times.
✓ Branch 46 taken 17014 times.
✓ Branch 47 taken 52545 times.
523238 : (notEqual(a[1], b[1]) ? a[1] < b[1]
1328 382628 : (a[2] < b[2])));
1329 });
1330
1331 14576 const auto squaredEps = eps*eps;
1332
2/2
✓ Branch 2 taken 2660 times.
✓ Branch 3 taken 5633 times.
14576 points.erase(std::unique(
1333 points.begin(), points.end(),
1334 319572 [squaredEps] (const auto& a, const auto&b) { return (b-a).two_norm2() < squaredEps; }),
1335 14576 points.end()
1336 );
1337
1338 // return false if we don't have more than four unique points (dim+1)
1339
2/2
✓ Branch 0 taken 2660 times.
✓ Branch 1 taken 5633 times.
14576 if (points.size() < 4)
1340 return false;
1341
1342 // check if the points are coplanar (then we don't have a 3-dimensional intersection)
1343 24161 const bool coplanar = [&]
1344 {
1345 5633 const auto p0 = points[0];
1346 16899 const auto normal = crossProduct(points[1] - p0, points[2] - p0);
1347 // include the normal in eps (instead of norm*norm) since the normal can become very small
1348 // if the first three points are very close together
1349 5633 const auto epsCoplanar = normal.two_norm()*norm*eps_;
1350
4/4
✓ Branch 0 taken 4154 times.
✓ Branch 1 taken 23 times.
✓ Branch 2 taken 4528 times.
✓ Branch 3 taken 2400 times.
11105 for (int i = 3; i < points.size(); ++i)
1351 {
1352 17364 const auto ad = points[i] - p0;
1353 using std::abs;
1354
4/4
✓ Branch 0 taken 2146 times.
✓ Branch 1 taken 2008 times.
✓ Branch 2 taken 1064 times.
✓ Branch 3 taken 3464 times.
8682 if (abs(normal*ad) > epsCoplanar)
1355 3210 return false;
1356 }
1357
1358 return true;
1359 9264 }();
1360
1361
2/2
✓ Branch 0 taken 2423 times.
✓ Branch 1 taken 3210 times.
9264 if (coplanar)
1362 return false;
1363
1364 // we return the intersection as point cloud (that can be triangulated later)
1365
1/2
✓ Branch 1 taken 3210 times.
✗ Branch 2 not taken.
4426 intersection = points;
1366
1367 return true;
1368 14668 }
1369
1370 /*!
1371 * \brief Colliding segment and convex polyhedron
1372 * \param geo1/geo2 The geometries to intersect
1373 * \param intersection Container to store the intersection result
1374 * \todo implement overloads for polygon-, segment- or point-like intersections
1375 */
1376 template<class P = Policy, std::enable_if_t<P::dimIntersection != 3, int> = 0>
1377 static bool intersection(const Geometry1& geo1, const Geometry2& geo2, Intersection& intersection)
1378 {
1379 static_assert(int(dimworld) == int(Geometry2::coorddimension), "Can only collide geometries of same coordinate dimension");
1380 DUNE_THROW(Dune::NotImplemented, "Polyhedron-polygon intersection detection only implemented for polygon-like intersections");
1381 }
1382 };
1383
1384 /*!
1385 * \ingroup Geometry
1386 * \brief A class for polygon--segment intersection in 3d space
1387 */
1388 template <class Geometry1, class Geometry2, class Policy>
1389 class GeometryIntersection<Geometry1, Geometry2, Policy, 3, 2, 1>
1390 {
1391 enum { dimworld = 3 };
1392 enum { dim1 = 2 };
1393 enum { dim2 = 1 };
1394
1395 public:
1396 using ctype = typename Policy::ctype;
1397 using Point = typename Policy::Point;
1398 using Intersection = typename Policy::Intersection;
1399
1400 private:
1401 static constexpr ctype eps_ = 1.5e-7; // base epsilon for floating point comparisons
1402
1403 public:
1404 /*!
1405 * \brief Colliding segment and convex polyhedron
1406 * \note Algorithm based on the one from "Real-Time Collision Detection" by Christer Ericson,
1407 * published by Morgan Kaufmann Publishers, (c) 2005 Elsevier Inc. (Chapter 5.3.6)
1408 * \param geo1/geo2 The geometries to intersect
1409 * \param intersection If the geometries collide, is holds the corner points of
1410 * the intersection object in global coordinates.
1411 * \note This overload is used when point-like intersections are seeked
1412 */
1413 template<class P = Policy, std::enable_if_t<P::dimIntersection == 1, int> = 0>
1414 387377 static bool intersection(const Geometry1& geo1, const Geometry2& geo2, Intersection& intersection)
1415 {
1416 static_assert(int(dimworld) == int(Geometry2::coorddimension), "Can only collide geometries of same coordinate dimension");
1417
1418 ctype tfirst, tlast;
1419
2/2
✓ Branch 1 taken 83418 times.
✓ Branch 2 taken 303898 times.
387377 if (intersect_(geo1, geo2, tfirst, tlast))
1420 {
1421 // the intersection exists. Export the intersections geometry now:
1422 // s(t) = a + t(b-a) in [tfirst, tlast]
1423 166882 intersection = Intersection({geo2.global(tfirst), geo2.global(tlast)});
1424 83461 return true;
1425 }
1426
1427 return false;
1428 }
1429
1430 /*!
1431 * \brief Colliding segment and convex polyhedron
1432 * \note Algorithm based on the one from "Real-Time Collision Detection" by Christer Ericson,
1433 * published by Morgan Kaufmann Publishers, (c) 2005 Elsevier Inc. (Chapter 5.3.6)
1434 * \param geo1/geo2 The geometries to intersect
1435 * \param is If the geometries collide, is holds the corner points of
1436 * the intersection object in global coordinates.
1437 * \note This overload is used when point-like intersections are seeked
1438 */
1439 template<class P = Policy, std::enable_if_t<P::dimIntersection == 0, int> = 0>
1440 3282916 static bool intersection(const Geometry1& geo1, const Geometry2& geo2, Intersection& is)
1441 {
1442 static_assert(int(dimworld) == int(Geometry2::coorddimension), "Can only collide geometries of same coordinate dimension");
1443
1444 3282916 const auto p = geo2.corner(0);
1445 3282916 const auto q = geo2.corner(1);
1446
1447 3282916 const auto a = geo1.corner(0);
1448 3282916 const auto b = geo1.corner(1);
1449 3282916 const auto c = geo1.corner(2);
1450
1451
2/2
✓ Branch 0 taken 464047 times.
✓ Branch 1 taken 1671835 times.
3244324 if (geo1.corners() == 3)
1452 783135 return intersect_<Policy>(a, b, c, p, q, is);
1453
1454
1/2
✓ Branch 0 taken 1671835 times.
✗ Branch 1 not taken.
2461189 else if (geo1.corners() == 4)
1455 {
1456 2499781 Intersection is1, is2;
1457 bool hasSegment1, hasSegment2;
1458
1459 2499781 const auto d = geo1.corner(3);
1460
1/2
✓ Branch 1 taken 19296 times.
✗ Branch 2 not taken.
2499781 const bool intersects1 = intersect_<Policy>(a, b, d, p, q, is1, hasSegment1);
1461
1/2
✓ Branch 1 taken 19296 times.
✗ Branch 2 not taken.
2499781 const bool intersects2 = intersect_<Policy>(a, d, c, p, q, is2, hasSegment2);
1462
1463
4/4
✓ Branch 0 taken 1658191 times.
✓ Branch 1 taken 32940 times.
✓ Branch 2 taken 1626008 times.
✓ Branch 3 taken 32183 times.
2499781 if (hasSegment1 || hasSegment2)
1464 return false;
1465
1466
2/2
✓ Branch 0 taken 102473 times.
✓ Branch 1 taken 1523535 times.
2420704 if (intersects1) { is = is1; return true; }
1467
2/2
✓ Branch 0 taken 52572 times.
✓ Branch 1 taken 1470963 times.
2296417 if (intersects2) { is = is2; return true; }
1468
1469 return false;
1470 }
1471
1472 else
1473 DUNE_THROW(Dune::NotImplemented, "Collision of segment and geometry of type "
1474 << geo1.type() << ", "<< geo1.corners() << " corners.");
1475 }
1476
1477 private:
1478 /*!
1479 * \brief Obtain local coordinates of start/end point of the intersecting segment.
1480 */
1481 template<class P = Policy, std::enable_if_t<P::dimIntersection == 1, int> = 0>
1482 387377 static bool intersect_(const Geometry1& geo1, const Geometry2& geo2, ctype& tfirst, ctype& tlast)
1483 {
1484 // lambda to obtain the facet corners on geo1
1485 387316 auto getFacetCorners = [] (const Geometry1& geo1)
1486 {
1487 387316 std::vector< std::array<int, 2> > facetCorners;
1488
3/6
✗ Branch 0 not taken.
✓ Branch 1 taken 387292 times.
✗ Branch 2 not taken.
✓ Branch 3 taken 13 times.
✓ Branch 4 taken 11 times.
✗ Branch 5 not taken.
387316 switch (geo1.corners())
1489 {
1490 13 case 4: // quadrilateral
1491
1/4
✗ Branch 1 not taken.
✗ Branch 2 not taken.
✓ Branch 4 taken 13 times.
✗ Branch 5 not taken.
13 facetCorners = {{0, 2}, {3, 1}, {1, 0}, {2, 3}};
1492 13 break;
1493 387303 case 3: // triangle
1494
2/8
✓ Branch 1 taken 387292 times.
✗ Branch 2 not taken.
✗ Branch 3 not taken.
✗ Branch 4 not taken.
✓ Branch 6 taken 11 times.
✗ Branch 7 not taken.
✗ Branch 8 not taken.
✗ Branch 9 not taken.
387303 facetCorners = {{1, 0}, {0, 2}, {2, 1}};
1495 387303 break;
1496 default:
1497 DUNE_THROW(Dune::NotImplemented, "Collision of segment and geometry of type "
1498 << geo1.type() << " with "<< geo1.corners() << " corners.");
1499 }
1500
1501 387316 return facetCorners;
1502 };
1503
1504 387377 const auto center1 = geo1.center();
1505 387425 const auto normal1 = crossProduct(geo1.corner(1) - geo1.corner(0),
1506 774754 geo1.corner(2) - geo1.corner(0));
1507
1508 // lambda to obtain the normal on a facet
1509 1204754 auto computeNormal = [&center1, &normal1, &geo1] (const std::array<int, 2>& facetCorners)
1510 {
1511 817283 const auto c0 = geo1.corner(facetCorners[0]);
1512 817377 const auto c1 = geo1.corner(facetCorners[1]);
1513 817377 const auto edge = c1 - c0;
1514
1515 817377 Dune::FieldVector<ctype, dimworld> n = crossProduct(edge, normal1);
1516 817377 n /= n.two_norm();
1517
1518 // orientation of the element is not known
1519 // make sure normal points outwards of element
1520
2/4
✓ Branch 0 taken 817293 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 84 times.
✗ Branch 3 not taken.
2452131 if ( n*(center1-c0) > 0.0 )
1521 817377 n *= -1.0;
1522
1523 817377 return n;
1524 };
1525
1526 387377 return Detail::computeSegmentIntersection(geo1, geo2, eps_, tfirst, tlast, getFacetCorners, computeNormal);
1527 }
1528
1529 /*!
1530 * \brief triangle--segment point-like intersection with points as input.
1531 */
1532 template<class P = Policy, std::enable_if_t<P::dimIntersection == 0, int> = 0>
1533 464047 static bool intersect_(const Point& a, const Point& b, const Point& c,
1534 const Point& p, const Point& q,
1535 Intersection& is)
1536 {
1537 bool hasSegment;
1538 464047 return intersect_(a, b, c, p, q, is, hasSegment);
1539 }
1540
1541 /*!
1542 * \brief triangle--segment point-like intersection with points as input. Also
1543 * stores if a segment-like intersection was found in the provided boolean.
1544 */
1545 template<class P = Policy, std::enable_if_t<P::dimIntersection == 0, int> = 0>
1546 3846309 static bool intersect_(const Point& a, const Point& b, const Point& c,
1547 const Point& p, const Point& q,
1548 Intersection& is, bool& hasSegmentIs)
1549 {
1550 3846309 hasSegmentIs = false;
1551
1552 3846309 const auto ab = b - a;
1553 3846309 const auto ac = c - a;
1554 3846309 const auto qp = p - q;
1555
1556 // compute the triangle normal that defines the triangle plane
1557 3846309 const auto normal = crossProduct(ab, ac);
1558
1559 // compute the denominator
1560 // if denom is 0 the segment is parallel and we can return
1561
2/2
✓ Branch 0 taken 5729763 times.
✓ Branch 1 taken 1909921 times.
15385236 const auto denom = normal*qp;
1562 3846309 const auto abnorm2 = ab.two_norm2();
1563
2/2
✓ Branch 0 taken 1157013 times.
✓ Branch 1 taken 752908 times.
7692618 const auto eps = eps_*abnorm2*qp.two_norm();
1564 using std::abs;
1565
2/2
✓ Branch 0 taken 1157013 times.
✓ Branch 1 taken 752908 times.
3846309 if (abs(denom) < eps)
1566 {
1567 1758853 const auto pa = a - p;
1568 1758853 const auto denom2 = normal*pa;
1569
2/2
✓ Branch 0 taken 864893 times.
✓ Branch 1 taken 292120 times.
3517706 if (abs(denom2) > eps_*pa.two_norm()*abnorm2)
1570 return false;
1571
1572 // if we get here, we are in-plane. Check if a
1573 // segment-like intersection with geometry 1 exists.
1574 using SegmentPolicy = typename IntersectionPolicy::SegmentPolicy<ctype, dimworld>;
1575 using Triangle = Dune::AffineGeometry<ctype, 2, dimworld>;
1576 using Segment = Dune::AffineGeometry<ctype, 1, dimworld>;
1577 using SegmentIntersectionAlgorithm = GeometryIntersection<Triangle, Segment, SegmentPolicy>;
1578 using SegmentIntersectionType = typename SegmentIntersectionAlgorithm::Intersection;
1579 387292 SegmentIntersectionType segmentIs;
1580
1581
1/2
✓ Branch 1 taken 292120 times.
✗ Branch 2 not taken.
387292 Triangle triangle(Dune::GeometryTypes::simplex(2), std::array<Point, 3>({a, b, c}));
1582
1/2
✓ Branch 1 taken 292120 times.
✗ Branch 2 not taken.
387292 Segment segment(Dune::GeometryTypes::simplex(1), std::array<Point, 2>({p, q}));
1583
3/4
✓ Branch 1 taken 292120 times.
✗ Branch 2 not taken.
✓ Branch 3 taken 58012 times.
✓ Branch 4 taken 234108 times.
387292 if (SegmentIntersectionAlgorithm::intersection(triangle, segment, segmentIs))
1584 {
1585 83398 hasSegmentIs = true;
1586 83398 return false;
1587 }
1588
1589 // We are in-plane. A point-like
1590 // intersection can only be on the edges
1591
2/2
✓ Branch 0 taken 424188 times.
✓ Branch 1 taken 146602 times.
778354 for (const auto& ip : {p, q})
1592 {
1593 563146 if ( intersectsPointSimplex(ip, a, b)
1594
2/2
✓ Branch 1 taken 344380 times.
✓ Branch 2 taken 25067 times.
507945 || intersectsPointSimplex(ip, b, c)
1595
4/4
✓ Branch 0 taken 369447 times.
✓ Branch 1 taken 54741 times.
✓ Branch 3 taken 7698 times.
✓ Branch 4 taken 336682 times.
1045944 || intersectsPointSimplex(ip, c, a) )
1596 {
1597 88686 is = ip;
1598 88686 return true;
1599 }
1600 }
1601
1602 215208 return false;
1603 }
1604
1605 // compute intersection t value of pq with plane of triangle.
1606 // a segment intersects if and only if 0 <= t <= 1.
1607 2087456 const auto ap = p - a;
1608 2087456 const auto t = (ap*normal)/denom;
1609
2/2
✓ Branch 0 taken 155229 times.
✓ Branch 1 taken 597679 times.
2087456 if (t < 0.0 - eps_) return false;
1610
2/2
✓ Branch 0 taken 148182 times.
✓ Branch 1 taken 449497 times.
1589635 if (t > 1.0 + eps_) return false;
1611
1612 // compute the barycentric coordinates and check if the intersection point
1613 // is inside the bounds of the triangle
1614 1102240 const auto e = crossProduct(qp, ap);
1615 1102240 const auto v = (ac*e)/denom;
1616
4/4
✓ Branch 0 taken 116047 times.
✓ Branch 1 taken 333450 times.
✓ Branch 2 taken 71437 times.
✓ Branch 3 taken 262013 times.
1102240 if (v < -eps_ || v > 1.0 + eps_) return false;
1617 448814 const auto w = -(ab*e)/denom;
1618
4/4
✓ Branch 0 taken 60319 times.
✓ Branch 1 taken 201694 times.
✓ Branch 2 taken 35874 times.
✓ Branch 3 taken 165820 times.
448814 if (w < -eps_ || v + w > 1.0 + eps_) return false;
1619
1620 // Now we are sure there is an intersection points
1621 // Perform delayed division compute the last barycentric coordinate component
1622 234923 const auto u = 1.0 - v - w;
1623
1624 234923 Point ip(0.0);
1625
2/2
✓ Branch 0 taken 497460 times.
✓ Branch 1 taken 165820 times.
939692 ip.axpy(u, a);
1626
2/2
✓ Branch 0 taken 497460 times.
✓ Branch 1 taken 165820 times.
939692 ip.axpy(v, b);
1627 234923 ip.axpy(w, c);
1628 234923 is = ip;
1629 234923 return true;
1630 }
1631 };
1632
1633 /*!
1634 * \ingroup Geometry
1635 * \brief A class for segment--polygon intersection in 3d space
1636 */
1637 template <class Geometry1, class Geometry2, class Policy>
1638 class GeometryIntersection<Geometry1, Geometry2, Policy, 3, 1, 2>
1639 : public GeometryIntersection<Geometry2, Geometry1, Policy, 3, 2, 1>
1640 {
1641 using Base = GeometryIntersection<Geometry2, Geometry1, Policy, 3, 2, 1>;
1642 public:
1643 /*!
1644 * \brief Colliding segment and convex polygon
1645 * \param geo1/geo2 The geometries to intersect
1646 * \param intersection If the geometries collide intersection holds the
1647 * corner points of the intersection object in global coordinates.
1648 * \note This forwards to the polyhedron-polygon specialization with swapped arguments.
1649 */
1650 template<class P = Policy>
1651 static bool intersection(const Geometry1& geo1, const Geometry2& geo2, typename Base::Intersection& intersection)
1652 {
1653 return Base::intersection(geo2, geo1, intersection);
1654 }
1655 };
1656
1657 /*!
1658 * \ingroup Geometry
1659 * \brief A class for segment--segment intersection in 3d space
1660 */
1661 template <class Geometry1, class Geometry2, class Policy>
1662 class GeometryIntersection<Geometry1, Geometry2, Policy, 3, 1, 1>
1663 {
1664 enum { dimworld = 3 };
1665 enum { dim1 = 1 };
1666 enum { dim2 = 1 };
1667
1668 public:
1669 using ctype = typename Policy::ctype;
1670 using Point = typename Policy::Point;
1671 using Intersection = typename Policy::Intersection;
1672
1673 private:
1674 static constexpr ctype eps_ = 1.5e-7; // base epsilon for floating point comparisons
1675
1676 public:
1677 /*!
1678 * \brief Colliding two segments
1679 * \param geo1/geo2 The geometries to intersect
1680 * \param intersection The intersection point
1681 * \note This overload is used when point-like intersections are seeked
1682 */
1683 template<class P = Policy, std::enable_if_t<P::dimIntersection == 0, int> = 0>
1684 418 static bool intersection(const Geometry1& geo1, const Geometry2& geo2, Intersection& intersection)
1685 {
1686 static_assert(int(dimworld) == int(Geometry2::coorddimension), "Can only collide geometries of same coordinate dimension");
1687
1688 418 const auto v1 = geo1.corner(1) - geo1.corner(0);
1689 418 const auto v2 = geo2.corner(1) - geo2.corner(0);
1690 836 const auto ac = geo2.corner(0) - geo1.corner(0);
1691
1692 418 const auto v1Norm2 = v1.two_norm2();
1693 418 const auto eps2 = eps_*v1Norm2;
1694
1695 418 const auto n = crossProduct(v1, v2);
1696
1697 // first check if segments are parallel
1698 using std::abs;
1699
2/2
✓ Branch 0 taken 100 times.
✓ Branch 1 taken 318 times.
418 if ( n.two_norm2() < eps2*v1Norm2 )
1700 {
1701 // check if they lie on the same line
1702
2/2
✓ Branch 1 taken 49 times.
✓ Branch 2 taken 51 times.
200 if (crossProduct(v1, ac).two_norm2() > eps2)
1703 return false;
1704
1705 // they lie on the same line,
1706 // if so, point intersection can only be one of the corners
1707 51 const auto sp = v1*v2;
1708
2/2
✓ Branch 0 taken 9 times.
✓ Branch 1 taken 42 times.
51 if ( sp < 0.0 )
1709 {
1710
2/2
✓ Branch 0 taken 4 times.
✓ Branch 1 taken 5 times.
9 if ( ac.two_norm2() < eps2 )
1711 4 { intersection = geo2.corner(0); return true; }
1712
1713
1/2
✗ Branch 2 not taken.
✓ Branch 3 taken 5 times.
15 if ( (geo2.corner(1) - geo1.corner(1)).two_norm2() < eps2 )
1714 { intersection = geo2.corner(1); return true; }
1715 }
1716 else
1717 {
1718
2/2
✓ Branch 2 taken 4 times.
✓ Branch 3 taken 38 times.
126 if ( (geo2.corner(1) - geo1.corner(0)).two_norm2() < eps2 )
1719 4 { intersection = geo2.corner(1); return true; }
1720
1721
2/2
✓ Branch 2 taken 8 times.
✓ Branch 3 taken 30 times.
114 if ( (geo2.corner(0) - geo1.corner(1)).two_norm2() < eps2 )
1722 8 { intersection = geo2.corner(0); return true; }
1723 }
1724
1725 // no intersection
1726 35 return false;
1727 }
1728
1729 // in-plane normal vector on v1
1730 318 const auto v1Normal = crossProduct(v1, n);
1731
1732 // intersection point on v2 in local coords
1733 318 const auto t2 = - 1.0*(ac*v1Normal) / (v2*v1Normal);
1734
1735 // check if the local coords are valid
1736
4/4
✓ Branch 0 taken 64 times.
✓ Branch 1 taken 254 times.
✓ Branch 2 taken 40 times.
✓ Branch 3 taken 214 times.
318 if (t2 < -1.0*eps_ || t2 > 1.0 + eps_)
1737 return false;
1738
1739
2/2
✓ Branch 2 taken 162 times.
✓ Branch 3 taken 52 times.
214 if (auto ip = geo2.global(t2); intersectsPointGeometry(ip, geo1))
1740 162 { intersection = std::move(ip); return true; }
1741
1742 52 return false;
1743 }
1744
1745 /*!
1746 * \brief Colliding two segments in 3D
1747 * \param geo1/geo2 The geometries to intersect
1748 * \param intersection If the geometries collide, is holds the corner points of
1749 * the intersection object in global coordinates.
1750 * \note This overload is used when segment-like intersections are seeked
1751 */
1752 template<class P = Policy, std::enable_if_t<P::dimIntersection == 1, int> = 0>
1753 478 static bool intersection(const Geometry1& geo1, const Geometry2& geo2, Intersection& intersection)
1754 {
1755 static_assert(int(dimworld) == int(Geometry2::coorddimension), "Can only collide geometries of same coordinate dimension");
1756
1757 478 const auto& a = geo1.corner(0);
1758 478 const auto& b = geo1.corner(1);
1759 478 const auto ab = b-a;
1760
1761 478 const auto& p = geo2.corner(0);
1762 478 const auto& q = geo2.corner(1);
1763 478 const auto pq = q-p;
1764
1765 478 const auto abNorm2 = ab.two_norm2();
1766
2/2
✓ Branch 0 taken 35 times.
✓ Branch 1 taken 443 times.
478 const auto pqNorm2 = pq.two_norm2();
1767
1768 using std::max;
1769 478 const auto eps2 = eps_*max(abNorm2, pqNorm2);
1770
1771 // if the segment are not parallel there is no segment intersection
1772 using std::abs;
1773
2/2
✓ Branch 1 taken 4 times.
✓ Branch 2 taken 474 times.
956 if (crossProduct(ab, pq).two_norm2() > eps2*eps2)
1774 return false;
1775
1776 474 const auto ap = (p-a);
1777 474 const auto aq = (q-a);
1778
1779 // points have to be colinear
1780
2/2
✓ Branch 1 taken 4 times.
✓ Branch 2 taken 470 times.
948 if (crossProduct(ap, aq).two_norm2() > eps2*eps2)
1781 return false;
1782
1783 // scaled local coordinates
1784 // we save the division for the normalization for now
1785 // and do it in the very end if we find an intersection
1786 470 auto tp = ap*ab;
1787 470 auto tq = aq*ab;
1788
1789 // make sure they are sorted
1790 using std::swap;
1791
2/2
✓ Branch 0 taken 33 times.
✓ Branch 1 taken 437 times.
470 if (tp > tq)
1792 33 swap(tp, tq);
1793
1794 using std::clamp;
1795
2/2
✓ Branch 0 taken 136 times.
✓ Branch 1 taken 334 times.
470 tp = clamp(tp, 0.0, abNorm2);
1796
2/2
✓ Branch 0 taken 4 times.
✓ Branch 1 taken 466 times.
470 tq = clamp(tq, 0.0, abNorm2);
1797
1798
2/2
✓ Branch 0 taken 132 times.
✓ Branch 1 taken 338 times.
470 if (abs(tp-tq) < eps2)
1799 return false;
1800
1801 338 intersection = Intersection({geo1.global(tp/abNorm2), geo1.global(tq/abNorm2)});
1802 338 return true;
1803 }
1804 };
1805
1806 } // end namespace Dumux
1807
1808 #endif
1809