implementation.hpp 14 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461
  1. // Boost.Geometry (aka GGL, Generic Geometry Library)
  2. // Copyright (c) 2007-2015 Barend Gehrels, Amsterdam, the Netherlands.
  3. // Copyright (c) 2008-2015 Bruno Lalande, Paris, France.
  4. // Copyright (c) 2009-2015 Mateusz Loskot, London, UK.
  5. // Copyright (c) 2013-2015 Adam Wulkiewicz, Lodz, Poland.
  6. // This file was modified by Oracle on 2013, 2014, 2015, 2017, 2019.
  7. // Modifications copyright (c) 2013-2019, Oracle and/or its affiliates.
  8. // Contributed and/or modified by Adam Wulkiewicz, on behalf of Oracle
  9. // Parts of Boost.Geometry are redesigned from Geodan's Geographic Library
  10. // (geolib/GGL), copyright (c) 1995-2010 Geodan, Amsterdam, the Netherlands.
  11. // Use, modification and distribution is subject to the Boost Software License,
  12. // Version 1.0. (See accompanying file LICENSE_1_0.txt or copy at
  13. // http://www.boost.org/LICENSE_1_0.txt)
  14. #ifndef BOOST_GEOMETRY_ALGORITHMS_DETAIL_TOUCHES_IMPLEMENTATION_HPP
  15. #define BOOST_GEOMETRY_ALGORITHMS_DETAIL_TOUCHES_IMPLEMENTATION_HPP
  16. #include <boost/geometry/algorithms/detail/for_each_range.hpp>
  17. #include <boost/geometry/algorithms/detail/overlay/overlay.hpp>
  18. #include <boost/geometry/algorithms/detail/overlay/self_turn_points.hpp>
  19. #include <boost/geometry/algorithms/detail/sub_range.hpp>
  20. #include <boost/geometry/algorithms/detail/relate/relate_impl.hpp>
  21. #include <boost/geometry/algorithms/detail/touches/interface.hpp>
  22. #include <boost/geometry/algorithms/disjoint.hpp>
  23. #include <boost/geometry/algorithms/intersects.hpp>
  24. #include <boost/geometry/algorithms/num_geometries.hpp>
  25. #include <boost/geometry/algorithms/relate.hpp>
  26. #include <boost/geometry/policies/robustness/no_rescale_policy.hpp>
  27. namespace boost { namespace geometry
  28. {
  29. #ifndef DOXYGEN_NO_DETAIL
  30. namespace detail { namespace touches
  31. {
  32. // Box/Box
  33. template
  34. <
  35. std::size_t Dimension,
  36. std::size_t DimensionCount
  37. >
  38. struct box_box_loop
  39. {
  40. template <typename Box1, typename Box2>
  41. static inline bool apply(Box1 const& b1, Box2 const& b2, bool & touch)
  42. {
  43. typedef typename coordinate_type<Box1>::type coordinate_type1;
  44. typedef typename coordinate_type<Box2>::type coordinate_type2;
  45. coordinate_type1 const& min1 = get<min_corner, Dimension>(b1);
  46. coordinate_type1 const& max1 = get<max_corner, Dimension>(b1);
  47. coordinate_type2 const& min2 = get<min_corner, Dimension>(b2);
  48. coordinate_type2 const& max2 = get<max_corner, Dimension>(b2);
  49. // TODO assert or exception?
  50. //BOOST_GEOMETRY_ASSERT(min1 <= max1 && min2 <= max2);
  51. if (max1 < min2 || max2 < min1)
  52. {
  53. return false;
  54. }
  55. if (max1 == min2 || max2 == min1)
  56. {
  57. touch = true;
  58. }
  59. return box_box_loop
  60. <
  61. Dimension + 1,
  62. DimensionCount
  63. >::apply(b1, b2, touch);
  64. }
  65. };
  66. template
  67. <
  68. std::size_t DimensionCount
  69. >
  70. struct box_box_loop<DimensionCount, DimensionCount>
  71. {
  72. template <typename Box1, typename Box2>
  73. static inline bool apply(Box1 const& , Box2 const&, bool &)
  74. {
  75. return true;
  76. }
  77. };
  78. struct box_box
  79. {
  80. template <typename Box1, typename Box2, typename Strategy>
  81. static inline bool apply(Box1 const& b1, Box2 const& b2, Strategy const& /*strategy*/)
  82. {
  83. BOOST_STATIC_ASSERT((boost::is_same
  84. <
  85. typename geometry::coordinate_system<Box1>::type,
  86. typename geometry::coordinate_system<Box2>::type
  87. >::value
  88. ));
  89. assert_dimension_equal<Box1, Box2>();
  90. bool touches = false;
  91. bool ok = box_box_loop
  92. <
  93. 0,
  94. dimension<Box1>::type::value
  95. >::apply(b1, b2, touches);
  96. return ok && touches;
  97. }
  98. };
  99. // Areal/Areal
  100. struct areal_interrupt_policy
  101. {
  102. static bool const enabled = true;
  103. bool found_touch;
  104. bool found_not_touch;
  105. // dummy variable required by self_get_turn_points::get_turns
  106. static bool const has_intersections = false;
  107. inline bool result()
  108. {
  109. return found_touch && !found_not_touch;
  110. }
  111. inline areal_interrupt_policy()
  112. : found_touch(false), found_not_touch(false)
  113. {}
  114. template <typename Range>
  115. inline bool apply(Range const& range)
  116. {
  117. // if already rejected (temp workaround?)
  118. if ( found_not_touch )
  119. return true;
  120. typedef typename boost::range_iterator<Range const>::type iterator;
  121. for ( iterator it = boost::begin(range) ; it != boost::end(range) ; ++it )
  122. {
  123. if ( it->has(overlay::operation_intersection) )
  124. {
  125. found_not_touch = true;
  126. return true;
  127. }
  128. switch(it->method)
  129. {
  130. case overlay::method_crosses:
  131. found_not_touch = true;
  132. return true;
  133. case overlay::method_equal:
  134. // Segment spatially equal means: at the right side
  135. // the polygon internally overlaps. So return false.
  136. found_not_touch = true;
  137. return true;
  138. case overlay::method_touch:
  139. case overlay::method_touch_interior:
  140. case overlay::method_collinear:
  141. if ( ok_for_touch(*it) )
  142. {
  143. found_touch = true;
  144. }
  145. else
  146. {
  147. found_not_touch = true;
  148. return true;
  149. }
  150. break;
  151. case overlay::method_none :
  152. case overlay::method_disjoint :
  153. case overlay::method_error :
  154. break;
  155. }
  156. }
  157. return false;
  158. }
  159. template <typename Turn>
  160. inline bool ok_for_touch(Turn const& turn)
  161. {
  162. return turn.both(overlay::operation_union)
  163. || turn.both(overlay::operation_blocked)
  164. || turn.combination(overlay::operation_union, overlay::operation_blocked)
  165. ;
  166. }
  167. };
  168. template<typename Geometry, typename PointInRingStrategy>
  169. struct check_each_ring_for_within
  170. {
  171. bool has_within;
  172. Geometry const& m_geometry;
  173. PointInRingStrategy const& m_strategy;
  174. inline check_each_ring_for_within(Geometry const& g, PointInRingStrategy const& strategy)
  175. : has_within(false)
  176. , m_geometry(g)
  177. , m_strategy(strategy)
  178. {}
  179. template <typename Range>
  180. inline void apply(Range const& range)
  181. {
  182. typename geometry::point_type<Range>::type p;
  183. geometry::point_on_border(p, range);
  184. if ( !has_within && geometry::within(p, m_geometry, m_strategy) )
  185. {
  186. has_within = true;
  187. }
  188. }
  189. };
  190. template <typename FirstGeometry, typename SecondGeometry, typename IntersectionStrategy>
  191. inline bool rings_containing(FirstGeometry const& geometry1,
  192. SecondGeometry const& geometry2,
  193. IntersectionStrategy const& strategy)
  194. {
  195. // NOTE: This strategy could be defined inside IntersectionStrategy
  196. typedef typename IntersectionStrategy::template point_in_geometry_strategy
  197. <
  198. FirstGeometry, SecondGeometry
  199. >::type point_in_ring_strategy_type;
  200. point_in_ring_strategy_type point_in_ring_strategy
  201. = strategy.template get_point_in_geometry_strategy<FirstGeometry, SecondGeometry>();
  202. check_each_ring_for_within
  203. <
  204. FirstGeometry, point_in_ring_strategy_type
  205. > checker(geometry1, point_in_ring_strategy);
  206. geometry::detail::for_each_range(geometry2, checker);
  207. return checker.has_within;
  208. }
  209. template <typename Geometry1, typename Geometry2>
  210. struct areal_areal
  211. {
  212. template <typename IntersectionStrategy>
  213. static inline bool apply(Geometry1 const& geometry1,
  214. Geometry2 const& geometry2,
  215. IntersectionStrategy const& strategy)
  216. {
  217. typedef typename geometry::point_type<Geometry1>::type point_type;
  218. typedef detail::overlay::turn_info<point_type> turn_info;
  219. std::deque<turn_info> turns;
  220. detail::touches::areal_interrupt_policy policy;
  221. boost::geometry::get_turns
  222. <
  223. detail::overlay::do_reverse<geometry::point_order<Geometry1>::value>::value,
  224. detail::overlay::do_reverse<geometry::point_order<Geometry2>::value>::value,
  225. detail::overlay::assign_null_policy
  226. >(geometry1, geometry2, strategy, detail::no_rescale_policy(), turns, policy);
  227. return policy.result()
  228. && ! geometry::detail::touches::rings_containing(geometry1, geometry2, strategy)
  229. && ! geometry::detail::touches::rings_containing(geometry2, geometry1, strategy);
  230. }
  231. };
  232. // P/*
  233. struct use_point_in_geometry
  234. {
  235. template <typename Point, typename Geometry, typename Strategy>
  236. static inline bool apply(Point const& point, Geometry const& geometry, Strategy const& strategy)
  237. {
  238. return detail::within::point_in_geometry(point, geometry, strategy) == 0;
  239. }
  240. };
  241. }}
  242. #endif // DOXYGEN_NO_DETAIL
  243. #ifndef DOXYGEN_NO_DISPATCH
  244. namespace dispatch {
  245. // P/P
  246. template <typename Geometry1, typename Geometry2>
  247. struct touches<Geometry1, Geometry2, point_tag, point_tag, pointlike_tag, pointlike_tag, false>
  248. {
  249. template <typename Strategy>
  250. static inline bool apply(Geometry1 const& , Geometry2 const& , Strategy const&)
  251. {
  252. return false;
  253. }
  254. };
  255. template <typename Geometry1, typename Geometry2>
  256. struct touches<Geometry1, Geometry2, point_tag, multi_point_tag, pointlike_tag, pointlike_tag, false>
  257. {
  258. template <typename Strategy>
  259. static inline bool apply(Geometry1 const& , Geometry2 const& , Strategy const&)
  260. {
  261. return false;
  262. }
  263. };
  264. template <typename Geometry1, typename Geometry2>
  265. struct touches<Geometry1, Geometry2, multi_point_tag, multi_point_tag, pointlike_tag, pointlike_tag, false>
  266. {
  267. template <typename Strategy>
  268. static inline bool apply(Geometry1 const&, Geometry2 const&, Strategy const&)
  269. {
  270. return false;
  271. }
  272. };
  273. // P/L P/A
  274. template <typename Point, typename Geometry, typename Tag2, typename CastedTag2>
  275. struct touches<Point, Geometry, point_tag, Tag2, pointlike_tag, CastedTag2, false>
  276. : detail::touches::use_point_in_geometry
  277. {};
  278. template <typename MultiPoint, typename MultiGeometry, typename Tag2, typename CastedTag2>
  279. struct touches<MultiPoint, MultiGeometry, multi_point_tag, Tag2, pointlike_tag, CastedTag2, false>
  280. : detail::relate::relate_impl
  281. <
  282. detail::de9im::static_mask_touches_type,
  283. MultiPoint,
  284. MultiGeometry
  285. >
  286. {};
  287. // L/P A/P
  288. template <typename Geometry, typename MultiPoint, typename Tag1, typename CastedTag1>
  289. struct touches<Geometry, MultiPoint, Tag1, multi_point_tag, CastedTag1, pointlike_tag, false>
  290. : detail::relate::relate_impl
  291. <
  292. detail::de9im::static_mask_touches_type,
  293. Geometry,
  294. MultiPoint
  295. >
  296. {};
  297. // Box/Box
  298. template <typename Box1, typename Box2, typename CastedTag1, typename CastedTag2>
  299. struct touches<Box1, Box2, box_tag, box_tag, CastedTag1, CastedTag2, false>
  300. : detail::touches::box_box
  301. {};
  302. template <typename Box1, typename Box2>
  303. struct touches<Box1, Box2, box_tag, box_tag, areal_tag, areal_tag, false>
  304. : detail::touches::box_box
  305. {};
  306. // L/L
  307. template <typename Linear1, typename Linear2, typename Tag1, typename Tag2>
  308. struct touches<Linear1, Linear2, Tag1, Tag2, linear_tag, linear_tag, false>
  309. : detail::relate::relate_impl
  310. <
  311. detail::de9im::static_mask_touches_type,
  312. Linear1,
  313. Linear2
  314. >
  315. {};
  316. // L/A
  317. template <typename Linear, typename Areal, typename Tag1, typename Tag2>
  318. struct touches<Linear, Areal, Tag1, Tag2, linear_tag, areal_tag, false>
  319. : detail::relate::relate_impl
  320. <
  321. detail::de9im::static_mask_touches_type,
  322. Linear,
  323. Areal
  324. >
  325. {};
  326. // A/L
  327. template <typename Linear, typename Areal, typename Tag1, typename Tag2>
  328. struct touches<Areal, Linear, Tag1, Tag2, areal_tag, linear_tag, false>
  329. : detail::relate::relate_impl
  330. <
  331. detail::de9im::static_mask_touches_type,
  332. Areal,
  333. Linear
  334. >
  335. {};
  336. // A/A
  337. template <typename Areal1, typename Areal2, typename Tag1, typename Tag2>
  338. struct touches<Areal1, Areal2, Tag1, Tag2, areal_tag, areal_tag, false>
  339. : detail::relate::relate_impl
  340. <
  341. detail::de9im::static_mask_touches_type,
  342. Areal1,
  343. Areal2
  344. >
  345. {};
  346. template <typename Areal1, typename Areal2>
  347. struct touches<Areal1, Areal2, ring_tag, ring_tag, areal_tag, areal_tag, false>
  348. : detail::touches::areal_areal<Areal1, Areal2>
  349. {};
  350. } // namespace dispatch
  351. #endif // DOXYGEN_NO_DISPATCH
  352. namespace resolve_variant
  353. {
  354. template <typename Geometry>
  355. struct self_touches
  356. {
  357. static bool apply(Geometry const& geometry)
  358. {
  359. concepts::check<Geometry const>();
  360. typedef typename strategy::relate::services::default_strategy
  361. <
  362. Geometry, Geometry
  363. >::type strategy_type;
  364. typedef typename geometry::point_type<Geometry>::type point_type;
  365. typedef detail::overlay::turn_info<point_type> turn_info;
  366. typedef detail::overlay::get_turn_info
  367. <
  368. detail::overlay::assign_null_policy
  369. > policy_type;
  370. std::deque<turn_info> turns;
  371. detail::touches::areal_interrupt_policy policy;
  372. strategy_type strategy;
  373. // TODO: skip_adjacent should be set to false
  374. detail::self_get_turn_points::get_turns
  375. <
  376. false, policy_type
  377. >::apply(geometry, strategy, detail::no_rescale_policy(), turns, policy, 0, true);
  378. return policy.result();
  379. }
  380. };
  381. }
  382. }} // namespace boost::geometry
  383. #endif // BOOST_GEOMETRY_ALGORITHMS_DETAIL_TOUCHES_IMPLEMENTATION_HPP