// Boost.Geometry (aka GGL, Generic Geometry Library) // Copyright (c) 2012-2020 Barend Gehrels, Amsterdam, the Netherlands. // Use, modification and distribution is subject to the Boost Software License, // Version 1.0. (See accompanying file LICENSE_1_0.txt or copy at // http://www.boost.org/LICENSE_1_0.txt) #ifndef BOOST_GEOMETRY_ALGORITHMS_DETAIL_BUFFER_LINE_LINE_INTERSECTION_HPP #define BOOST_GEOMETRY_ALGORITHMS_DETAIL_BUFFER_LINE_LINE_INTERSECTION_HPP #include #include #include namespace boost { namespace geometry { #ifndef DOXYGEN_NO_DETAIL namespace detail { namespace buffer { struct line_line_intersection { template static Point between_point(Point const& a, Point const& b) { Point result; geometry::set<0>(result, (geometry::get<0>(a) + geometry::get<0>(b)) / 2.0); geometry::set<1>(result, (geometry::get<1>(a) + geometry::get<1>(b)) / 2.0); return result; } template static bool apply(Point const& pi, Point const& pj, Point const& qi, Point const& qj, Point const& vertex, bool equidistant, Point& ip) { // Calculates ip (below) by either intersecting p (pi, pj) // with q (qi, qj) or by taking a point between pj and qi (b) and // intersecting r (b, v), where v is the original vertex, with p (or q). // The reason for dual approach: p might be nearly collinear with q, // and in that case the intersection points can lose precision // (or be plainly wrong). // Therefore it takes the most precise option (this is usually p, r) // // /qj | // / | // / / | // / / | // / / | // /qi / | // / | // ip * + b * v | // \ | // \pj \ | // \ \ | // \ \ | // \ \ | // \pi \ | // // If generated sides along the segments can have an adapted distance, // in a custom strategy, then the calculation of the point in between // might be incorrect and the optimization is not used. using ct = typename coordinate_type::type; auto const p = detail::make::make_infinite_line(pi, pj); auto const q = detail::make::make_infinite_line(qi, qj); using line = decltype(p); using arithmetic::determinant; using arithmetic::assign_intersection_point; // The denominator is the determinant of (a,b) values of lines p q // | pa pa | // | qb qb | auto const denominator_pq = determinant(p, q); static decltype(denominator_pq) const zero = 0; if (equidistant) { auto const between = between_point(pj, qi); auto const r = detail::make::make_infinite_line(vertex, between); auto const denominator_pr = determinant(p, r); if (math::equals(denominator_pq, zero) && math::equals(denominator_pr, zero)) { // Degenerate case (for example when length results in ) return false; } ip = geometry::math::abs(denominator_pq) > geometry::math::abs(denominator_pr) ? assign_intersection_point(p, q, denominator_pq) : assign_intersection_point(p, r, denominator_pr); } else { if (math::equals(denominator_pq, zero)) { return false; } ip = assign_intersection_point(p, q, denominator_pq); } return true; } }; }} // namespace detail::buffer #endif // DOXYGEN_NO_DETAIL }} // namespace boost::geometry #endif // BOOST_GEOMETRY_ALGORITHMS_DETAIL_BUFFER_LINE_LINE_INTERSECTION_HPP