point_point.hpp 9.2 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285
  1. // Boost.Geometry (aka GGL, Generic Geometry Library)
  2. // Copyright (c) 2007-2012 Barend Gehrels, Amsterdam, the Netherlands.
  3. // Copyright (c) 2023-2024 Adam Wulkiewicz, Lodz, Poland.
  4. // This file was modified by Oracle on 2013-2022.
  5. // Modifications copyright (c) 2013-2023, Oracle and/or its affiliates.
  6. // Contributed and/or modified by Vissarion Fysikopoulos, on behalf of Oracle
  7. // Contributed and/or modified by Adam Wulkiewicz, on behalf of Oracle
  8. // Use, modification and distribution is subject to the Boost Software License,
  9. // Version 1.0. (See accompanying file LICENSE_1_0.txt or copy at
  10. // http://www.boost.org/LICENSE_1_0.txt)
  11. #ifndef BOOST_GEOMETRY_ALGORITHMS_DETAIL_RELATE_POINT_POINT_HPP
  12. #define BOOST_GEOMETRY_ALGORITHMS_DETAIL_RELATE_POINT_POINT_HPP
  13. #include <algorithm>
  14. #include <vector>
  15. #include <boost/range/empty.hpp>
  16. #include <boost/range/size.hpp>
  17. #include <boost/geometry/algorithms/detail/equals/point_point.hpp>
  18. #include <boost/geometry/algorithms/detail/within/point_in_geometry.hpp>
  19. #include <boost/geometry/algorithms/detail/relate/result.hpp>
  20. #include <boost/geometry/policies/compare.hpp>
  21. namespace boost { namespace geometry
  22. {
  23. #ifndef DOXYGEN_NO_DETAIL
  24. namespace detail { namespace relate {
  25. template <typename Point1, typename Point2>
  26. struct point_point
  27. {
  28. static const bool interruption_enabled = false;
  29. template <typename Result, typename Strategy>
  30. static inline void apply(Point1 const& point1, Point2 const& point2,
  31. Result & result,
  32. Strategy const& strategy)
  33. {
  34. bool equal = detail::equals::equals_point_point(point1, point2, strategy);
  35. if ( equal )
  36. {
  37. update<interior, interior, '0'>(result);
  38. }
  39. else
  40. {
  41. update<interior, exterior, '0'>(result);
  42. update<exterior, interior, '0'>(result);
  43. }
  44. update<exterior, exterior, result_dimension<Point1>::value>(result);
  45. }
  46. };
  47. template <typename Point, typename MultiPoint, typename EqPPStrategy>
  48. std::pair<bool, bool> point_multipoint_check(Point const& point,
  49. MultiPoint const& multi_point,
  50. EqPPStrategy const& strategy)
  51. {
  52. bool found_inside = false;
  53. bool found_outside = false;
  54. // point_in_geometry could be used here but why iterate over MultiPoint twice?
  55. // we must search for a point in the exterior because all points in MultiPoint can be equal
  56. auto const end = boost::end(multi_point);
  57. for (auto it = boost::begin(multi_point); it != end; ++it)
  58. {
  59. bool ii = detail::equals::equals_point_point(point, *it, strategy);
  60. if (ii)
  61. {
  62. found_inside = true;
  63. }
  64. else
  65. {
  66. found_outside = true;
  67. }
  68. if (found_inside && found_outside)
  69. {
  70. break;
  71. }
  72. }
  73. return std::make_pair(found_inside, found_outside);
  74. }
  75. template <typename Point, typename MultiPoint, bool Transpose = false>
  76. struct point_multipoint
  77. {
  78. static const bool interruption_enabled = false;
  79. template <typename Result, typename Strategy>
  80. static inline void apply(Point const& point, MultiPoint const& multi_point,
  81. Result & result,
  82. Strategy const& strategy)
  83. {
  84. if ( boost::empty(multi_point) )
  85. {
  86. // TODO: throw on empty input?
  87. update<interior, exterior, '0', Transpose>(result);
  88. return;
  89. }
  90. std::pair<bool, bool> rel = point_multipoint_check(point, multi_point, strategy);
  91. if ( rel.first ) // some point of MP is equal to P
  92. {
  93. update<interior, interior, '0', Transpose>(result);
  94. if ( rel.second ) // a point of MP was found outside P
  95. {
  96. update<exterior, interior, '0', Transpose>(result);
  97. }
  98. }
  99. else
  100. {
  101. update<interior, exterior, '0', Transpose>(result);
  102. update<exterior, interior, '0', Transpose>(result);
  103. }
  104. update<exterior, exterior, result_dimension<Point>::value, Transpose>(result);
  105. }
  106. };
  107. template <typename MultiPoint, typename Point>
  108. struct multipoint_point
  109. {
  110. static const bool interruption_enabled = false;
  111. template <typename Result, typename Strategy>
  112. static inline void apply(MultiPoint const& multi_point, Point const& point,
  113. Result & result,
  114. Strategy const& strategy)
  115. {
  116. point_multipoint<Point, MultiPoint, true>::apply(point, multi_point, result, strategy);
  117. }
  118. };
  119. template <typename MultiPoint1, typename MultiPoint2>
  120. struct multipoint_multipoint
  121. {
  122. static const bool interruption_enabled = true;
  123. template <typename Result, typename Strategy>
  124. static inline void apply(MultiPoint1 const& multi_point1, MultiPoint2 const& multi_point2,
  125. Result & result,
  126. Strategy const& /*strategy*/)
  127. {
  128. {
  129. // TODO: throw on empty input?
  130. bool empty1 = boost::empty(multi_point1);
  131. bool empty2 = boost::empty(multi_point2);
  132. if ( empty1 && empty2 )
  133. {
  134. return;
  135. }
  136. else if ( empty1 )
  137. {
  138. update<exterior, interior, '0'>(result);
  139. return;
  140. }
  141. else if ( empty2 )
  142. {
  143. update<interior, exterior, '0'>(result);
  144. return;
  145. }
  146. }
  147. // The geometry containing smaller number of points will be analysed first
  148. if ( boost::size(multi_point1) < boost::size(multi_point2) )
  149. {
  150. search_both<false, Strategy>(multi_point1, multi_point2, result);
  151. }
  152. else
  153. {
  154. search_both<true, Strategy>(multi_point2, multi_point1, result);
  155. }
  156. update<exterior, exterior, result_dimension<MultiPoint1>::value>(result);
  157. }
  158. template <bool Transpose, typename Strategy, typename MPt1, typename MPt2, typename Result>
  159. static inline void search_both(MPt1 const& first_sorted_mpt, MPt2 const& first_iterated_mpt,
  160. Result & result)
  161. {
  162. if ( relate::may_update<interior, interior, '0'>(result)
  163. || relate::may_update<interior, exterior, '0'>(result)
  164. || relate::may_update<exterior, interior, '0'>(result) )
  165. {
  166. // NlogN + MlogN
  167. bool const is_disjoint = search<Transpose, Strategy>(first_sorted_mpt, first_iterated_mpt, result);
  168. if (is_disjoint || BOOST_GEOMETRY_CONDITION(result.interrupt) )
  169. {
  170. return;
  171. }
  172. }
  173. if ( relate::may_update<interior, interior, '0'>(result)
  174. || relate::may_update<interior, exterior, '0'>(result)
  175. || relate::may_update<exterior, interior, '0'>(result) )
  176. {
  177. // MlogM + NlogM
  178. search<! Transpose, Strategy>(first_iterated_mpt, first_sorted_mpt, result);
  179. }
  180. }
  181. template <bool Transpose,
  182. typename Strategy,
  183. typename SortedMultiPoint,
  184. typename IteratedMultiPoint,
  185. typename Result>
  186. static inline bool search(SortedMultiPoint const& sorted_mpt,
  187. IteratedMultiPoint const& iterated_mpt,
  188. Result & result)
  189. {
  190. // sort points from the 1 MPt
  191. typedef typename geometry::point_type<SortedMultiPoint>::type point_type;
  192. typedef geometry::less<void, -1, Strategy> less_type;
  193. std::vector<point_type> points(boost::begin(sorted_mpt), boost::end(sorted_mpt));
  194. less_type const less = less_type();
  195. std::sort(points.begin(), points.end(), less);
  196. bool found_inside = false;
  197. bool found_outside = false;
  198. // for each point in the second MPt
  199. for (auto it = boost::begin(iterated_mpt); it != boost::end(iterated_mpt); ++it)
  200. {
  201. bool ii = std::binary_search(points.begin(), points.end(), *it, less);
  202. if (ii)
  203. {
  204. found_inside = true;
  205. }
  206. else
  207. {
  208. found_outside = true;
  209. }
  210. if (found_inside && found_outside)
  211. {
  212. break;
  213. }
  214. }
  215. if ( found_inside ) // some point of MP2 is equal to some of MP1
  216. {
  217. // TODO: if I/I is set for one MPt, this won't be changed when the other one in analysed
  218. // so if e.g. only I/I must be analysed we musn't check the other MPt
  219. update<interior, interior, '0', Transpose>(result);
  220. if ( found_outside ) // some point of MP2 was found outside of MP1
  221. {
  222. update<exterior, interior, '0', Transpose>(result);
  223. }
  224. }
  225. else
  226. {
  227. update<interior, exterior, '0', Transpose>(result);
  228. update<exterior, interior, '0', Transpose>(result);
  229. }
  230. // if no point is intersecting the other MPt then we musn't analyse the reversed case
  231. return ! found_inside;
  232. }
  233. };
  234. }} // namespace detail::relate
  235. #endif // DOXYGEN_NO_DETAIL
  236. }} // namespace boost::geometry
  237. #endif // BOOST_GEOMETRY_ALGORITHMS_DETAIL_RELATE_POINT_POINT_HPP