point_point.hpp 9.2 KB

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