side_robust.hpp 5.6 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185
  1. // Boost.Geometry (aka GGL, Generic Geometry Library)
  2. // Copyright (c) 2019 Tinko Bartels, Berlin, Germany.
  3. // Contributed and/or modified by Tinko Bartels,
  4. // as part of Google Summer of Code 2019 program.
  5. // This file was modified by Oracle on 2021.
  6. // Modifications copyright (c) 2021, Oracle and/or its affiliates.
  7. // Contributed and/or modified by Vissarion Fysikopoulos, on behalf of Oracle
  8. // Contributed and/or modified by Adam Wulkiewicz, on behalf of Oracle
  9. // Use, modification and distribution is subject to the Boost Software License,
  10. // Version 1.0. (See accompanying file LICENSE_1_0.txt or copy at
  11. // http://www.boost.org/LICENSE_1_0.txt)
  12. #ifndef BOOST_GEOMETRY_STRATEGY_CARTESIAN_SIDE_ROBUST_HPP
  13. #define BOOST_GEOMETRY_STRATEGY_CARTESIAN_SIDE_ROBUST_HPP
  14. #include <boost/geometry/core/config.hpp>
  15. #include <boost/geometry/strategy/cartesian/side_non_robust.hpp>
  16. #include <boost/geometry/strategies/side.hpp>
  17. #include <boost/geometry/util/select_most_precise.hpp>
  18. #include <boost/geometry/util/select_calculation_type.hpp>
  19. #include <boost/geometry/util/precise_math.hpp>
  20. #include <boost/geometry/util/math.hpp>
  21. namespace boost { namespace geometry
  22. {
  23. namespace strategy { namespace side
  24. {
  25. struct epsilon_equals_policy
  26. {
  27. public:
  28. template <typename Policy, typename T1, typename T2>
  29. static bool apply(T1 const& a, T2 const& b, Policy const& policy)
  30. {
  31. return boost::geometry::math::detail::equals_by_policy(a, b, policy);
  32. }
  33. };
  34. struct fp_equals_policy
  35. {
  36. public:
  37. template <typename Policy, typename T1, typename T2>
  38. static bool apply(T1 const& a, T2 const& b, Policy const&)
  39. {
  40. return a == b;
  41. }
  42. };
  43. /*!
  44. \brief Adaptive precision predicate to check at which side of a segment a point lies:
  45. left of segment (>0), right of segment (< 0), on segment (0).
  46. \ingroup strategies
  47. \tparam CalculationType \tparam_calculation (numeric_limits<ct>::epsilon() and numeric_limits<ct>::digits must be supported for calculation type ct)
  48. \tparam Robustness std::size_t value from 0 (fastest) to 3 (default, guarantees correct results).
  49. \details This predicate determines at which side of a segment a point lies using an algorithm that is adapted from orient2d as described in "Adaptive Precision Floating-Point Arithmetic and Fast Robust Geometric Predicates" by Jonathan Richard Shewchuk ( https://dl.acm.org/citation.cfm?doid=237218.237337 ). More information and copies of the paper can also be found at https://www.cs.cmu.edu/~quake/robust.html . It is designed to be adaptive in the sense that it should be fast for inputs that lead to correct results with plain float operations but robust for inputs that require higher precision arithmetics.
  50. */
  51. template
  52. <
  53. typename CalculationType = void,
  54. typename EqualsPolicy = epsilon_equals_policy,
  55. std::size_t Robustness = 3
  56. >
  57. struct side_robust
  58. {
  59. template <typename CT>
  60. struct epsilon_policy
  61. {
  62. using Policy = boost::geometry::math::detail::equals_factor_policy<CT>;
  63. epsilon_policy() {}
  64. template <typename Type>
  65. epsilon_policy(Type const& a, Type const& b, Type const& c, Type const& d)
  66. : m_policy(a, b, c, d)
  67. {}
  68. Policy m_policy;
  69. public:
  70. template <typename T1, typename T2>
  71. bool apply(T1 a, T2 b) const
  72. {
  73. return EqualsPolicy::apply(a, b, m_policy);
  74. }
  75. };
  76. public:
  77. typedef cartesian_tag cs_tag;
  78. //! \brief Computes the sign of the CCW triangle p1, p2, p
  79. template
  80. <
  81. typename PromotedType,
  82. typename P1,
  83. typename P2,
  84. typename P,
  85. typename EpsPolicyInternal,
  86. std::enable_if_t<std::is_fundamental<PromotedType>::value, int> = 0
  87. >
  88. static inline PromotedType side_value(P1 const& p1,
  89. P2 const& p2,
  90. P const& p,
  91. EpsPolicyInternal& eps_policy)
  92. {
  93. using vec2d = ::boost::geometry::detail::precise_math::vec2d<PromotedType>;
  94. vec2d pa;
  95. pa.x = get<0>(p1);
  96. pa.y = get<1>(p1);
  97. vec2d pb;
  98. pb.x = get<0>(p2);
  99. pb.y = get<1>(p2);
  100. vec2d pc;
  101. pc.x = get<0>(p);
  102. pc.y = get<1>(p);
  103. return ::boost::geometry::detail::precise_math::orient2d
  104. <PromotedType, Robustness>(pa, pb, pc, eps_policy);
  105. }
  106. template
  107. <
  108. typename PromotedType,
  109. typename P1,
  110. typename P2,
  111. typename P,
  112. typename EpsPolicyInternal,
  113. std::enable_if_t<!std::is_fundamental<PromotedType>::value, int> = 0
  114. >
  115. static inline auto side_value(P1 const& p1, P2 const& p2, P const& p,
  116. EpsPolicyInternal&)
  117. {
  118. return side_non_robust<>::apply(p1, p2, p);
  119. }
  120. #ifndef DOXYGEN_SHOULD_SKIP_THIS
  121. template
  122. <
  123. typename P1,
  124. typename P2,
  125. typename P
  126. >
  127. static inline int apply(P1 const& p1, P2 const& p2, P const& p)
  128. {
  129. using coordinate_type = typename select_calculation_type_alt
  130. <
  131. CalculationType,
  132. P1,
  133. P2,
  134. P
  135. >::type;
  136. using promoted_type = typename select_most_precise
  137. <
  138. coordinate_type,
  139. double
  140. >::type;
  141. epsilon_policy<promoted_type> epsp;
  142. promoted_type sv = side_value<promoted_type>(p1, p2, p, epsp);
  143. promoted_type const zero = promoted_type();
  144. return epsp.apply(sv, zero) ? 0
  145. : sv > zero ? 1
  146. : -1;
  147. }
  148. #endif
  149. };
  150. }} // namespace strategy::side
  151. }} // namespace boost::geometry
  152. #endif // BOOST_GEOMETRY_STRATEGY_CARTESIAN_SIDE_ROBUST_HPP