From a5200767c9d9e4f27305ef5b8eb212e4cd78f47f Mon Sep 17 00:00:00 2001
From: "Dennis.Glaeser" <dennis.glaeser@iws.uni-stuttgart.de>
Date: Thu, 30 May 2019 12:32:30 +0200
Subject: [PATCH] [geometryintersection] add algo for 1d-1d intersections in 2d
 space

---
 dumux/common/geometry/geometryintersection.hh | 121 ++++++++++++++++++
 1 file changed, 121 insertions(+)

diff --git a/dumux/common/geometry/geometryintersection.hh b/dumux/common/geometry/geometryintersection.hh
index e3199636d7..91588c948b 100644
--- a/dumux/common/geometry/geometryintersection.hh
+++ b/dumux/common/geometry/geometryintersection.hh
@@ -32,6 +32,7 @@
 #include <dumux/common/math.hh>
 #include <dumux/common/geometry/intersectspointgeometry.hh>
 #include <dumux/common/geometry/grahamconvexhull.hh>
+#include <dumux/common/geometry/boundingboxtree.hh>
 
 namespace Dumux {
 namespace IntersectionPolicy {
@@ -214,6 +215,126 @@ public:
     }
 };
 
+/*!
+ * \ingroup Geometry
+ * \brief A class for segment--segment intersection in 2d space
+ */
+template <class Geometry1, class Geometry2, class Policy>
+class GeometryIntersection<Geometry1, Geometry2, Policy, 2, 1, 1>
+{
+    enum { dimworld = 2 };
+    enum { dim1 = 1 };
+    enum { dim2 = 1 };
+
+    // base epsilon for floating point comparisons
+    static constexpr typename Policy::ctype eps_ = 1.5e-7;
+
+public:
+    using ctype = typename Policy::ctype;
+    using Point = typename Policy::Point;
+    using Intersection = typename Policy::Intersection;
+
+    //! Deprecated alias, will be removed after 3.1
+    using IntersectionType DUNE_DEPRECATED_MSG("Please use Intersection instead") = Intersection;
+
+    /*!
+     * \brief Colliding two segments
+     * \param geo1/geo2 The geometries to intersect
+     * \param intersection The intersection point
+     * \note This overload is used when point-like intersections are seeked
+     */
+    template<class P = Policy, std::enable_if_t<P::dimIntersection == 0, int> = 0>
+    static bool intersection(const Geometry1& geo1, const Geometry2& geo2, Intersection& intersection)
+    {
+        static_assert(int(dimworld) == int(Geometry2::coorddimension), "Can only collide geometries of same coordinate dimension");
+
+        const auto v1 = geo1.corner(1) - geo1.corner(0);
+        const auto v2 = geo2.corner(1) - geo2.corner(0);
+        const auto ac = geo2.corner(0) - geo1.corner(0);
+
+        auto n2 = Point({-1.0*v2[1], v2[0]});
+        n2 /= n2.two_norm();
+
+        // compute distance of first corner on geo2 to line1
+        const auto dist12 = n2*ac;
+
+        // first check parallel segments
+        using std::abs;
+        using std::sqrt;
+
+        const auto v1Norm2 = v1.two_norm2();
+        const auto eps = eps_*sqrt(v1Norm2);
+        const auto eps2 = eps_*v1Norm2;
+
+        const auto sp = n2*v1;
+        if (abs(sp) < eps)
+        {
+            if (abs(dist12) > eps)
+                return false;
+
+            // point intersection can only be one of the corners
+            if ( (v1*v2) < 0.0 )
+            {
+                if ( ac.two_norm2() < eps2 )
+                { intersection = geo2.corner(0); return true; }
+
+                if ( (geo2.corner(1) - geo1.corner(1)).two_norm2() < eps2 )
+                { intersection = geo2.corner(1); return true; }
+            }
+            else
+            {
+                if ( (geo2.corner(1) - geo1.corner(0)).two_norm2() < eps2 )
+                { intersection = geo2.corner(1); return true; }
+
+                if ( (geo2.corner(0) - geo1.corner(1)).two_norm2() < eps2 )
+                { intersection = geo2.corner(0); return true; }
+            }
+
+            // no intersection
+            return false;
+        }
+
+        // intersection point on v1 in local coords
+        const auto t1 = dist12 / sp;
+
+        // check if the local coords are valid
+        if (t1 < -1.0*eps_ || t1 > 1.0 + eps_)
+            return false;
+
+        // compute global coordinates
+        auto isPoint = geo1.global(t1);
+
+        // check if point is in bounding box of v2
+        const auto c = geo2.corner(0);
+        const auto d = geo2.corner(1);
+
+        using std::min; using std::max;
+        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]) });
+
+        if ( intersectsPointBoundingBox(isPoint, bBox.data()) )
+        {
+            intersection = std::move(isPoint);
+            return true;
+        }
+
+        return false;
+    }
+
+    /*!
+     * \brief Colliding two segments
+     * \param geo1/geo2 The geometries to intersect
+     * \param intersection Container to store corners of intersection segment
+     * \note this overload is used when segment-like intersections are seeked
+     * \todo implement this query
+     */
+    template<class P = Policy, std::enable_if_t<P::dimIntersection == 1, int> = 0>
+    static bool intersection(const Geometry1& geo1, const Geometry2& geo2, Intersection& intersection)
+    {
+        static_assert(int(dimworld) == int(Geometry2::coorddimension), "Can only collide geometries of same coordinate dimension");
+        DUNE_THROW(Dune::NotImplemented, "segment-segment intersection detection for segment-like intersections");
+    }
+};
+
 /*!
  * \ingroup Geometry
  * \brief A class for polygon--segment intersection in 2d space
-- 
GitLab