point_to_range.hpp 7.7 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253
  1. // Boost.Geometry (aka GGL, Generic Geometry Library)
  2. // Copyright (c) 2014, Oracle and/or its affiliates.
  3. // Contributed and/or modified by Menelaos Karavelas, on behalf of Oracle
  4. // Licensed under the Boost Software License version 1.0.
  5. // http://www.boost.org/users/license.html
  6. #ifndef BOOST_GEOMETRY_ALGORITHMS_DETAIL_CLOSEST_FEATURE_POINT_TO_RANGE_HPP
  7. #define BOOST_GEOMETRY_ALGORITHMS_DETAIL_CLOSEST_FEATURE_POINT_TO_RANGE_HPP
  8. #include <utility>
  9. #include <boost/range.hpp>
  10. #include <boost/geometry/core/assert.hpp>
  11. #include <boost/geometry/core/closure.hpp>
  12. #include <boost/geometry/strategies/distance.hpp>
  13. #include <boost/geometry/util/math.hpp>
  14. namespace boost { namespace geometry
  15. {
  16. #ifndef DOXYGEN_NO_DETAIL
  17. namespace detail { namespace closest_feature
  18. {
  19. // returns the segment (pair of iterators) that realizes the closest
  20. // distance of the point to the range
  21. template
  22. <
  23. typename Point,
  24. typename Range,
  25. closure_selector Closure,
  26. typename Strategy
  27. >
  28. class point_to_point_range
  29. {
  30. protected:
  31. typedef typename boost::range_iterator<Range const>::type iterator_type;
  32. template <typename Distance>
  33. static inline void apply(Point const& point,
  34. iterator_type first,
  35. iterator_type last,
  36. Strategy const& strategy,
  37. iterator_type& it_min1,
  38. iterator_type& it_min2,
  39. Distance& dist_min)
  40. {
  41. BOOST_GEOMETRY_ASSERT( first != last );
  42. Distance const zero = Distance(0);
  43. iterator_type it = first;
  44. iterator_type prev = it++;
  45. if (it == last)
  46. {
  47. it_min1 = it_min2 = first;
  48. dist_min = strategy.apply(point, *first, *first);
  49. return;
  50. }
  51. // start with first segment distance
  52. dist_min = strategy.apply(point, *prev, *it);
  53. iterator_type prev_min_dist = prev;
  54. // check if other segments are closer
  55. for (++prev, ++it; it != last; ++prev, ++it)
  56. {
  57. Distance const dist = strategy.apply(point, *prev, *it);
  58. // Stop only if we find exactly zero distance
  59. // otherwise it may stop at some very small value and miss the min
  60. if (dist == zero)
  61. {
  62. dist_min = zero;
  63. it_min1 = prev;
  64. it_min2 = it;
  65. return;
  66. }
  67. else if (dist < dist_min)
  68. {
  69. dist_min = dist;
  70. prev_min_dist = prev;
  71. }
  72. }
  73. it_min1 = it_min2 = prev_min_dist;
  74. ++it_min2;
  75. }
  76. public:
  77. typedef typename std::pair<iterator_type, iterator_type> return_type;
  78. template <typename Distance>
  79. static inline return_type apply(Point const& point,
  80. iterator_type first,
  81. iterator_type last,
  82. Strategy const& strategy,
  83. Distance& dist_min)
  84. {
  85. iterator_type it_min1, it_min2;
  86. apply(point, first, last, strategy, it_min1, it_min2, dist_min);
  87. return std::make_pair(it_min1, it_min2);
  88. }
  89. static inline return_type apply(Point const& point,
  90. iterator_type first,
  91. iterator_type last,
  92. Strategy const& strategy)
  93. {
  94. typename strategy::distance::services::return_type
  95. <
  96. Strategy,
  97. Point,
  98. typename boost::range_value<Range>::type
  99. >::type dist_min;
  100. return apply(point, first, last, strategy, dist_min);
  101. }
  102. template <typename Distance>
  103. static inline return_type apply(Point const& point,
  104. Range const& range,
  105. Strategy const& strategy,
  106. Distance& dist_min)
  107. {
  108. return apply(point,
  109. boost::begin(range),
  110. boost::end(range),
  111. strategy,
  112. dist_min);
  113. }
  114. static inline return_type apply(Point const& point,
  115. Range const& range,
  116. Strategy const& strategy)
  117. {
  118. return apply(point, boost::begin(range), boost::end(range), strategy);
  119. }
  120. };
  121. // specialization for open ranges
  122. template <typename Point, typename Range, typename Strategy>
  123. class point_to_point_range<Point, Range, open, Strategy>
  124. : point_to_point_range<Point, Range, closed, Strategy>
  125. {
  126. private:
  127. typedef point_to_point_range<Point, Range, closed, Strategy> base_type;
  128. typedef typename base_type::iterator_type iterator_type;
  129. template <typename Distance>
  130. static inline void apply(Point const& point,
  131. iterator_type first,
  132. iterator_type last,
  133. Strategy const& strategy,
  134. iterator_type& it_min1,
  135. iterator_type& it_min2,
  136. Distance& dist_min)
  137. {
  138. BOOST_GEOMETRY_ASSERT( first != last );
  139. base_type::apply(point, first, last, strategy,
  140. it_min1, it_min2, dist_min);
  141. iterator_type it_back = --last;
  142. Distance const zero = Distance(0);
  143. Distance dist = strategy.apply(point, *it_back, *first);
  144. if (geometry::math::equals(dist, zero))
  145. {
  146. dist_min = zero;
  147. it_min1 = it_back;
  148. it_min2 = first;
  149. }
  150. else if (dist < dist_min)
  151. {
  152. dist_min = dist;
  153. it_min1 = it_back;
  154. it_min2 = first;
  155. }
  156. }
  157. public:
  158. typedef typename std::pair<iterator_type, iterator_type> return_type;
  159. template <typename Distance>
  160. static inline return_type apply(Point const& point,
  161. iterator_type first,
  162. iterator_type last,
  163. Strategy const& strategy,
  164. Distance& dist_min)
  165. {
  166. iterator_type it_min1, it_min2;
  167. apply(point, first, last, strategy, it_min1, it_min2, dist_min);
  168. return std::make_pair(it_min1, it_min2);
  169. }
  170. static inline return_type apply(Point const& point,
  171. iterator_type first,
  172. iterator_type last,
  173. Strategy const& strategy)
  174. {
  175. typedef typename strategy::distance::services::return_type
  176. <
  177. Strategy,
  178. Point,
  179. typename boost::range_value<Range>::type
  180. >::type distance_return_type;
  181. distance_return_type dist_min;
  182. return apply(point, first, last, strategy, dist_min);
  183. }
  184. template <typename Distance>
  185. static inline return_type apply(Point const& point,
  186. Range const& range,
  187. Strategy const& strategy,
  188. Distance& dist_min)
  189. {
  190. return apply(point,
  191. boost::begin(range),
  192. boost::end(range),
  193. strategy,
  194. dist_min);
  195. }
  196. static inline return_type apply(Point const& point,
  197. Range const& range,
  198. Strategy const& strategy)
  199. {
  200. return apply(point, boost::begin(range), boost::end(range), strategy);
  201. }
  202. };
  203. }} // namespace detail::closest_feature
  204. #endif // DOXYGEN_NO_DETAIL
  205. }} // namespace boost::geometry
  206. #endif // BOOST_GEOMETRY_ALGORITHMS_DETAIL_CLOSEST_FEATURE_POINT_TO_RANGE_HPP