diff --git a/include/boost/geometry/policies/relate/intersection_points.hpp b/include/boost/geometry/policies/relate/intersection_points.hpp index f4a811d5c..50f9b4312 100644 --- a/include/boost/geometry/policies/relate/intersection_points.hpp +++ b/include/boost/geometry/policies/relate/intersection_points.hpp @@ -82,7 +82,6 @@ struct segments_intersection_points >(numerator * dy_promoted / denominator)); } - template < typename Segment1, @@ -96,7 +95,33 @@ struct segments_intersection_points return_type result; result.count = 1; - if (sinfo.robust_ra < sinfo.robust_rb) + bool use_a = true; + + // Prefer one segment if one is on or near an endpoint + bool const a_near_end = sinfo.robust_ra.near_end(); + bool const b_near_end = sinfo.robust_rb.near_end(); + if (a_near_end && ! b_near_end) + { + use_a = true; + } + else if (b_near_end && ! a_near_end) + { + use_a = false; + } + else + { + // Prefer shorter segment + typedef typename SegmentIntersectionInfo::promoted_type ptype; + ptype const len_a = sinfo.dx_a * sinfo.dx_a + sinfo.dy_a * sinfo.dy_a; + ptype const len_b = sinfo.dx_b * sinfo.dx_b + sinfo.dy_b * sinfo.dy_b; + if (len_b < len_a) + { + use_a = false; + } + // else use_a is true but was already assigned like that + } + + if (use_a) { assign(result.intersections[0], s1, sinfo.robust_ra, sinfo.dx_a, sinfo.dy_a); diff --git a/include/boost/geometry/policies/robustness/segment_ratio.hpp b/include/boost/geometry/policies/robustness/segment_ratio.hpp index bf30f0295..ec659257a 100644 --- a/include/boost/geometry/policies/robustness/segment_ratio.hpp +++ b/include/boost/geometry/policies/robustness/segment_ratio.hpp @@ -139,14 +139,12 @@ public : m_denominator = -m_denominator; } - typedef typename promote_floating_point::type num_type; - static const num_type scale = 1000000.0; m_approximation = m_denominator == 0 ? 0 : boost::numeric_cast ( - boost::numeric_cast(m_numerator) * scale - / boost::numeric_cast(m_denominator) + boost::numeric_cast(m_numerator) * scale() + / boost::numeric_cast(m_denominator) ); } @@ -178,6 +176,18 @@ public : return m_numerator > m_denominator; } + inline bool near_end() const + { + if (left() || right()) + { + return false; + } + + static fp_type const small_part_of_scale = scale() / 100.0; + return m_approximation < small_part_of_scale + || m_approximation > scale() - small_part_of_scale; + } + inline bool close_to(thistype const& other) const { return geometry::math::abs(m_approximation - other.m_approximation) < 2; @@ -222,6 +232,8 @@ public : private : + typedef typename promote_floating_point::type fp_type; + Type m_numerator; Type m_denominator; @@ -230,7 +242,13 @@ private : // Boost.Rational is used if the approximations are close. // Reason: performance, Boost.Rational does a GCD by default and also the // comparisons contain while-loops. - double m_approximation; + fp_type m_approximation; + + + static inline fp_type scale() + { + return 1000000.0; + } };