segment_ratio.hpp 7.2 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267
  1. // Boost.Geometry (aka GGL, Generic Geometry Library)
  2. // Copyright (c) 2013 Barend Gehrels, Amsterdam, the Netherlands.
  3. // This file was modified by Oracle on 2016.
  4. // Modifications copyright (c) 2016 Oracle and/or its affiliates.
  5. // Contributed and/or modified by Adam Wulkiewicz, on behalf of Oracle
  6. // Use, modification and distribution is subject to the Boost Software License,
  7. // Version 1.0. (See accompanying file LICENSE_1_0.txt or copy at
  8. // http://www.boost.org/LICENSE_1_0.txt)
  9. #ifndef BOOST_GEOMETRY_POLICIES_ROBUSTNESS_SEGMENT_RATIO_HPP
  10. #define BOOST_GEOMETRY_POLICIES_ROBUSTNESS_SEGMENT_RATIO_HPP
  11. #include <boost/config.hpp>
  12. #include <boost/rational.hpp>
  13. #include <boost/geometry/core/assert.hpp>
  14. #include <boost/geometry/util/math.hpp>
  15. #include <boost/geometry/util/promote_floating_point.hpp>
  16. namespace boost { namespace geometry
  17. {
  18. namespace detail { namespace segment_ratio
  19. {
  20. template
  21. <
  22. typename Type,
  23. bool IsIntegral = boost::is_integral<Type>::type::value
  24. >
  25. struct less {};
  26. template <typename Type>
  27. struct less<Type, true>
  28. {
  29. template <typename Ratio>
  30. static inline bool apply(Ratio const& lhs, Ratio const& rhs)
  31. {
  32. return boost::rational<Type>(lhs.numerator(), lhs.denominator())
  33. < boost::rational<Type>(rhs.numerator(), rhs.denominator());
  34. }
  35. };
  36. template <typename Type>
  37. struct less<Type, false>
  38. {
  39. template <typename Ratio>
  40. static inline bool apply(Ratio const& lhs, Ratio const& rhs)
  41. {
  42. BOOST_GEOMETRY_ASSERT(lhs.denominator() != 0);
  43. BOOST_GEOMETRY_ASSERT(rhs.denominator() != 0);
  44. Type const a = lhs.numerator() / lhs.denominator();
  45. Type const b = rhs.numerator() / rhs.denominator();
  46. return ! geometry::math::equals(a, b)
  47. && a < b;
  48. }
  49. };
  50. template
  51. <
  52. typename Type,
  53. bool IsIntegral = boost::is_integral<Type>::type::value
  54. >
  55. struct equal {};
  56. template <typename Type>
  57. struct equal<Type, true>
  58. {
  59. template <typename Ratio>
  60. static inline bool apply(Ratio const& lhs, Ratio const& rhs)
  61. {
  62. return boost::rational<Type>(lhs.numerator(), lhs.denominator())
  63. == boost::rational<Type>(rhs.numerator(), rhs.denominator());
  64. }
  65. };
  66. template <typename Type>
  67. struct equal<Type, false>
  68. {
  69. template <typename Ratio>
  70. static inline bool apply(Ratio const& lhs, Ratio const& rhs)
  71. {
  72. BOOST_GEOMETRY_ASSERT(lhs.denominator() != 0);
  73. BOOST_GEOMETRY_ASSERT(rhs.denominator() != 0);
  74. Type const a = lhs.numerator() / lhs.denominator();
  75. Type const b = rhs.numerator() / rhs.denominator();
  76. return geometry::math::equals(a, b);
  77. }
  78. };
  79. }}
  80. //! Small class to keep a ratio (e.g. 1/4)
  81. //! Main purpose is intersections and checking on 0, 1, and smaller/larger
  82. //! The prototype used Boost.Rational. However, we also want to store FP ratios,
  83. //! (so numerator/denominator both in float)
  84. //! and Boost.Rational starts with GCD which we prefer to avoid if not necessary
  85. //! On a segment means: this ratio is between 0 and 1 (both inclusive)
  86. //!
  87. template <typename Type>
  88. class segment_ratio
  89. {
  90. public :
  91. typedef Type numeric_type;
  92. // Type-alias for the type itself
  93. typedef segment_ratio<Type> thistype;
  94. inline segment_ratio()
  95. : m_numerator(0)
  96. , m_denominator(1)
  97. , m_approximation(0)
  98. {}
  99. inline segment_ratio(const Type& nominator, const Type& denominator)
  100. : m_numerator(nominator)
  101. , m_denominator(denominator)
  102. {
  103. initialize();
  104. }
  105. inline Type const& numerator() const { return m_numerator; }
  106. inline Type const& denominator() const { return m_denominator; }
  107. inline void assign(const Type& nominator, const Type& denominator)
  108. {
  109. m_numerator = nominator;
  110. m_denominator = denominator;
  111. initialize();
  112. }
  113. inline void initialize()
  114. {
  115. // Minimal normalization
  116. // 1/-4 => -1/4, -1/-4 => 1/4
  117. if (m_denominator < 0)
  118. {
  119. m_numerator = -m_numerator;
  120. m_denominator = -m_denominator;
  121. }
  122. m_approximation =
  123. m_denominator == 0 ? 0
  124. : (
  125. boost::numeric_cast<fp_type>(m_numerator) * scale()
  126. / boost::numeric_cast<fp_type>(m_denominator)
  127. );
  128. }
  129. inline bool is_zero() const { return math::equals(m_numerator, 0); }
  130. inline bool is_one() const { return math::equals(m_numerator, m_denominator); }
  131. inline bool on_segment() const
  132. {
  133. // e.g. 0/4 or 4/4 or 2/4
  134. return m_numerator >= 0 && m_numerator <= m_denominator;
  135. }
  136. inline bool in_segment() const
  137. {
  138. // e.g. 1/4
  139. return m_numerator > 0 && m_numerator < m_denominator;
  140. }
  141. inline bool on_end() const
  142. {
  143. // e.g. 0/4 or 4/4
  144. return is_zero() || is_one();
  145. }
  146. inline bool left() const
  147. {
  148. // e.g. -1/4
  149. return m_numerator < 0;
  150. }
  151. inline bool right() const
  152. {
  153. // e.g. 5/4
  154. return m_numerator > m_denominator;
  155. }
  156. inline bool near_end() const
  157. {
  158. if (left() || right())
  159. {
  160. return false;
  161. }
  162. static fp_type const small_part_of_scale = scale() / 100;
  163. return m_approximation < small_part_of_scale
  164. || m_approximation > scale() - small_part_of_scale;
  165. }
  166. inline bool close_to(thistype const& other) const
  167. {
  168. return geometry::math::abs(m_approximation - other.m_approximation) < 50;
  169. }
  170. inline bool operator< (thistype const& other) const
  171. {
  172. return close_to(other)
  173. ? detail::segment_ratio::less<Type>::apply(*this, other)
  174. : m_approximation < other.m_approximation;
  175. }
  176. inline bool operator== (thistype const& other) const
  177. {
  178. return close_to(other)
  179. && detail::segment_ratio::equal<Type>::apply(*this, other);
  180. }
  181. static inline thistype zero()
  182. {
  183. static thistype result(0, 1);
  184. return result;
  185. }
  186. static inline thistype one()
  187. {
  188. static thistype result(1, 1);
  189. return result;
  190. }
  191. #if defined(BOOST_GEOMETRY_DEFINE_STREAM_OPERATOR_SEGMENT_RATIO)
  192. friend std::ostream& operator<<(std::ostream &os, segment_ratio const& ratio)
  193. {
  194. os << ratio.m_numerator << "/" << ratio.m_denominator
  195. << " (" << (static_cast<double>(ratio.m_numerator)
  196. / static_cast<double>(ratio.m_denominator))
  197. << ")";
  198. return os;
  199. }
  200. #endif
  201. private :
  202. // NOTE: if this typedef is used then fp_type is non-fundamental type
  203. // if Type is non-fundamental type
  204. //typedef typename promote_floating_point<Type>::type fp_type;
  205. typedef typename boost::mpl::if_c
  206. <
  207. boost::is_float<Type>::value, Type, double
  208. >::type fp_type;
  209. Type m_numerator;
  210. Type m_denominator;
  211. // Contains ratio on scale 0..1000000 (for 0..1)
  212. // This is an approximation for fast and rough comparisons
  213. // Boost.Rational is used if the approximations are close.
  214. // Reason: performance, Boost.Rational does a GCD by default and also the
  215. // comparisons contain while-loops.
  216. fp_type m_approximation;
  217. static inline fp_type scale()
  218. {
  219. return 1000000.0;
  220. }
  221. };
  222. }} // namespace boost::geometry
  223. #endif // BOOST_GEOMETRY_POLICIES_ROBUSTNESS_SEGMENT_RATIO_HPP