implementation.hpp 16 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540
  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-2022 Adam Wulkiewicz, Lodz, Poland.
  6. // This file was modified by Oracle on 2013-2022.
  7. // Modifications copyright (c) 2013-2022, 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 <type_traits>
  17. #include <boost/geometry/algorithms/detail/for_each_range.hpp>
  18. #include <boost/geometry/algorithms/detail/gc_topological_dimension.hpp>
  19. #include <boost/geometry/algorithms/detail/overlay/overlay.hpp>
  20. #include <boost/geometry/algorithms/detail/overlay/self_turn_points.hpp>
  21. #include <boost/geometry/algorithms/detail/sub_range.hpp>
  22. #include <boost/geometry/algorithms/detail/relate/implementation.hpp>
  23. #include <boost/geometry/algorithms/detail/relate/implementation_gc.hpp>
  24. #include <boost/geometry/algorithms/detail/relate/relate_impl.hpp>
  25. #include <boost/geometry/algorithms/detail/touches/interface.hpp>
  26. #include <boost/geometry/algorithms/detail/visit.hpp>
  27. #include <boost/geometry/algorithms/disjoint.hpp>
  28. #include <boost/geometry/algorithms/intersects.hpp>
  29. #include <boost/geometry/algorithms/num_geometries.hpp>
  30. #include <boost/geometry/geometries/helper_geometry.hpp>
  31. #include <boost/geometry/policies/robustness/no_rescale_policy.hpp>
  32. #include <boost/geometry/strategies/relate/cartesian.hpp>
  33. #include <boost/geometry/strategies/relate/geographic.hpp>
  34. #include <boost/geometry/strategies/relate/spherical.hpp>
  35. #include <boost/geometry/views/detail/geometry_collection_view.hpp>
  36. namespace boost { namespace geometry
  37. {
  38. #ifndef DOXYGEN_NO_DETAIL
  39. namespace detail { namespace touches
  40. {
  41. // Box/Box
  42. template
  43. <
  44. std::size_t Dimension,
  45. std::size_t DimensionCount
  46. >
  47. struct box_box_loop
  48. {
  49. template <typename Box1, typename Box2>
  50. static inline bool apply(Box1 const& b1, Box2 const& b2, bool & touch)
  51. {
  52. typedef typename coordinate_type<Box1>::type coordinate_type1;
  53. typedef typename coordinate_type<Box2>::type coordinate_type2;
  54. coordinate_type1 const& min1 = get<min_corner, Dimension>(b1);
  55. coordinate_type1 const& max1 = get<max_corner, Dimension>(b1);
  56. coordinate_type2 const& min2 = get<min_corner, Dimension>(b2);
  57. coordinate_type2 const& max2 = get<max_corner, Dimension>(b2);
  58. // TODO assert or exception?
  59. //BOOST_GEOMETRY_ASSERT(min1 <= max1 && min2 <= max2);
  60. if (max1 < min2 || max2 < min1)
  61. {
  62. return false;
  63. }
  64. if (max1 == min2 || max2 == min1)
  65. {
  66. touch = true;
  67. }
  68. return box_box_loop
  69. <
  70. Dimension + 1,
  71. DimensionCount
  72. >::apply(b1, b2, touch);
  73. }
  74. };
  75. template
  76. <
  77. std::size_t DimensionCount
  78. >
  79. struct box_box_loop<DimensionCount, DimensionCount>
  80. {
  81. template <typename Box1, typename Box2>
  82. static inline bool apply(Box1 const& , Box2 const&, bool &)
  83. {
  84. return true;
  85. }
  86. };
  87. struct box_box
  88. {
  89. template <typename Box1, typename Box2, typename Strategy>
  90. static inline bool apply(Box1 const& b1, Box2 const& b2, Strategy const& /*strategy*/)
  91. {
  92. BOOST_STATIC_ASSERT((std::is_same
  93. <
  94. typename geometry::coordinate_system<Box1>::type,
  95. typename geometry::coordinate_system<Box2>::type
  96. >::value
  97. ));
  98. assert_dimension_equal<Box1, Box2>();
  99. bool touches = false;
  100. bool ok = box_box_loop
  101. <
  102. 0,
  103. dimension<Box1>::type::value
  104. >::apply(b1, b2, touches);
  105. return ok && touches;
  106. }
  107. };
  108. // Areal/Areal
  109. struct areal_interrupt_policy
  110. {
  111. static bool const enabled = true;
  112. bool found_touch;
  113. bool found_not_touch;
  114. // dummy variable required by self_get_turn_points::get_turns
  115. static bool const has_intersections = false;
  116. inline bool result()
  117. {
  118. return found_touch && !found_not_touch;
  119. }
  120. inline areal_interrupt_policy()
  121. : found_touch(false), found_not_touch(false)
  122. {}
  123. template <typename Range>
  124. inline bool apply(Range const& range)
  125. {
  126. // if already rejected (temp workaround?)
  127. if (found_not_touch)
  128. {
  129. return true;
  130. }
  131. for (auto it = boost::begin(range); it != boost::end(range); ++it)
  132. {
  133. if (it->has(overlay::operation_intersection))
  134. {
  135. found_not_touch = true;
  136. return true;
  137. }
  138. switch (it->method)
  139. {
  140. case overlay::method_crosses:
  141. found_not_touch = true;
  142. return true;
  143. case overlay::method_equal:
  144. // Segment spatially equal means: at the right side
  145. // the polygon internally overlaps. So return false.
  146. found_not_touch = true;
  147. return true;
  148. case overlay::method_touch:
  149. case overlay::method_touch_interior:
  150. case overlay::method_collinear:
  151. if ( ok_for_touch(*it) )
  152. {
  153. found_touch = true;
  154. }
  155. else
  156. {
  157. found_not_touch = true;
  158. return true;
  159. }
  160. break;
  161. case overlay::method_start :
  162. case overlay::method_none :
  163. case overlay::method_disjoint :
  164. case overlay::method_error :
  165. break;
  166. }
  167. }
  168. return false;
  169. }
  170. template <typename Turn>
  171. inline bool ok_for_touch(Turn const& turn)
  172. {
  173. return turn.both(overlay::operation_union)
  174. || turn.both(overlay::operation_blocked)
  175. || turn.combination(overlay::operation_union, overlay::operation_blocked)
  176. ;
  177. }
  178. };
  179. template <typename Geometry1, typename Geometry2, typename Strategy>
  180. inline bool point_on_border_within(Geometry1 const& geometry1,
  181. Geometry2 const& geometry2,
  182. Strategy const& strategy)
  183. {
  184. using point_type = typename geometry::point_type<Geometry1>::type;
  185. typename helper_geometry<point_type>::type pt;
  186. return geometry::point_on_border(pt, geometry1)
  187. && geometry::within(pt, geometry2, strategy);
  188. }
  189. template <typename FirstGeometry, typename SecondGeometry, typename Strategy>
  190. inline bool rings_containing(FirstGeometry const& geometry1,
  191. SecondGeometry const& geometry2,
  192. Strategy const& strategy)
  193. {
  194. return geometry::detail::any_range_of(geometry2, [&](auto const& range)
  195. {
  196. return point_on_border_within(range, geometry1, strategy);
  197. });
  198. }
  199. template <typename Geometry1, typename Geometry2>
  200. struct areal_areal
  201. {
  202. template <typename Strategy>
  203. static inline bool apply(Geometry1 const& geometry1,
  204. Geometry2 const& geometry2,
  205. Strategy const& strategy)
  206. {
  207. using point_type = typename geometry::point_type<Geometry1>::type;
  208. using mutable_point_type = typename helper_geometry<point_type>::type;
  209. using turn_info = detail::overlay::turn_info<mutable_point_type>;
  210. std::deque<turn_info> turns;
  211. detail::touches::areal_interrupt_policy policy;
  212. geometry::get_turns
  213. <
  214. detail::overlay::do_reverse<geometry::point_order<Geometry1>::value>::value,
  215. detail::overlay::do_reverse<geometry::point_order<Geometry2>::value>::value,
  216. detail::overlay::assign_null_policy
  217. >(geometry1, geometry2, strategy, detail::no_rescale_policy(), turns, policy);
  218. return policy.result()
  219. && ! geometry::detail::touches::rings_containing(geometry1, geometry2, strategy)
  220. && ! geometry::detail::touches::rings_containing(geometry2, geometry1, strategy);
  221. }
  222. };
  223. // P/*
  224. struct use_point_in_geometry
  225. {
  226. template <typename Point, typename Geometry, typename Strategy>
  227. static inline bool apply(Point const& point, Geometry const& geometry, Strategy const& strategy)
  228. {
  229. return detail::within::point_in_geometry(point, geometry, strategy) == 0;
  230. }
  231. };
  232. // GC
  233. struct gc_gc
  234. {
  235. template <typename Geometry1, typename Geometry2, typename Strategy>
  236. static inline bool apply(Geometry1 const& geometry1, Geometry2 const& geometry2,
  237. Strategy const& strategy)
  238. {
  239. int const dimension1 = detail::gc_topological_dimension(geometry1);
  240. int const dimension2 = detail::gc_topological_dimension(geometry2);
  241. if (dimension1 == 0 && dimension2 == 0)
  242. {
  243. return false;
  244. }
  245. else
  246. {
  247. return detail::relate::relate_impl
  248. <
  249. detail::de9im::static_mask_touches_not_pp_type,
  250. Geometry1,
  251. Geometry2
  252. >::apply(geometry1, geometry2, strategy);
  253. }
  254. }
  255. };
  256. struct notgc_gc
  257. {
  258. template <typename Geometry1, typename Geometry2, typename Strategy>
  259. static inline bool apply(Geometry1 const& geometry1, Geometry2 const& geometry2,
  260. Strategy const& strategy)
  261. {
  262. using gc1_view_t = detail::geometry_collection_view<Geometry1>;
  263. return gc_gc::apply(gc1_view_t(geometry1), geometry2, strategy);
  264. }
  265. };
  266. struct gc_notgc
  267. {
  268. template <typename Geometry1, typename Geometry2, typename Strategy>
  269. static inline bool apply(Geometry1 const& geometry1, Geometry2 const& geometry2,
  270. Strategy const& strategy)
  271. {
  272. using gc2_view_t = detail::geometry_collection_view<Geometry2>;
  273. return gc_gc::apply(geometry1, gc2_view_t(geometry2), strategy);
  274. }
  275. };
  276. }}
  277. #endif // DOXYGEN_NO_DETAIL
  278. #ifndef DOXYGEN_NO_DISPATCH
  279. namespace dispatch {
  280. // P/P
  281. template <typename Geometry1, typename Geometry2>
  282. struct touches<Geometry1, Geometry2, point_tag, point_tag, pointlike_tag, pointlike_tag, false>
  283. {
  284. template <typename Strategy>
  285. static inline bool apply(Geometry1 const& , Geometry2 const& , Strategy const&)
  286. {
  287. return false;
  288. }
  289. };
  290. template <typename Geometry1, typename Geometry2>
  291. struct touches<Geometry1, Geometry2, point_tag, multi_point_tag, pointlike_tag, pointlike_tag, false>
  292. {
  293. template <typename Strategy>
  294. static inline bool apply(Geometry1 const& , Geometry2 const& , Strategy const&)
  295. {
  296. return false;
  297. }
  298. };
  299. template <typename Geometry1, typename Geometry2>
  300. struct touches<Geometry1, Geometry2, multi_point_tag, multi_point_tag, pointlike_tag, pointlike_tag, false>
  301. {
  302. template <typename Strategy>
  303. static inline bool apply(Geometry1 const&, Geometry2 const&, Strategy const&)
  304. {
  305. return false;
  306. }
  307. };
  308. // P/L P/A
  309. template <typename Point, typename Geometry, typename Tag2, typename CastedTag2>
  310. struct touches<Point, Geometry, point_tag, Tag2, pointlike_tag, CastedTag2, false>
  311. : detail::touches::use_point_in_geometry
  312. {};
  313. template <typename MultiPoint, typename MultiGeometry, typename Tag2, typename CastedTag2>
  314. struct touches<MultiPoint, MultiGeometry, multi_point_tag, Tag2, pointlike_tag, CastedTag2, false>
  315. : detail::relate::relate_impl
  316. <
  317. detail::de9im::static_mask_touches_type,
  318. MultiPoint,
  319. MultiGeometry
  320. >
  321. {};
  322. // L/P A/P
  323. template <typename Geometry, typename MultiPoint, typename Tag1, typename CastedTag1>
  324. struct touches<Geometry, MultiPoint, Tag1, multi_point_tag, CastedTag1, pointlike_tag, false>
  325. : detail::relate::relate_impl
  326. <
  327. detail::de9im::static_mask_touches_type,
  328. Geometry,
  329. MultiPoint
  330. >
  331. {};
  332. // Box/Box
  333. template <typename Box1, typename Box2, typename CastedTag1, typename CastedTag2>
  334. struct touches<Box1, Box2, box_tag, box_tag, CastedTag1, CastedTag2, false>
  335. : detail::touches::box_box
  336. {};
  337. template <typename Box1, typename Box2>
  338. struct touches<Box1, Box2, box_tag, box_tag, areal_tag, areal_tag, false>
  339. : detail::touches::box_box
  340. {};
  341. // L/L
  342. template <typename Linear1, typename Linear2, typename Tag1, typename Tag2>
  343. struct touches<Linear1, Linear2, Tag1, Tag2, linear_tag, linear_tag, false>
  344. : detail::relate::relate_impl
  345. <
  346. detail::de9im::static_mask_touches_type,
  347. Linear1,
  348. Linear2
  349. >
  350. {};
  351. // L/A
  352. template <typename Linear, typename Areal, typename Tag1, typename Tag2>
  353. struct touches<Linear, Areal, Tag1, Tag2, linear_tag, areal_tag, false>
  354. : detail::relate::relate_impl
  355. <
  356. detail::de9im::static_mask_touches_type,
  357. Linear,
  358. Areal
  359. >
  360. {};
  361. // A/L
  362. template <typename Linear, typename Areal, typename Tag1, typename Tag2>
  363. struct touches<Areal, Linear, Tag1, Tag2, areal_tag, linear_tag, false>
  364. : detail::relate::relate_impl
  365. <
  366. detail::de9im::static_mask_touches_type,
  367. Areal,
  368. Linear
  369. >
  370. {};
  371. // A/A
  372. template <typename Areal1, typename Areal2, typename Tag1, typename Tag2>
  373. struct touches<Areal1, Areal2, Tag1, Tag2, areal_tag, areal_tag, false>
  374. : detail::relate::relate_impl
  375. <
  376. detail::de9im::static_mask_touches_type,
  377. Areal1,
  378. Areal2
  379. >
  380. {};
  381. template <typename Areal1, typename Areal2>
  382. struct touches<Areal1, Areal2, ring_tag, ring_tag, areal_tag, areal_tag, false>
  383. : detail::touches::areal_areal<Areal1, Areal2>
  384. {};
  385. // GC
  386. template <typename Geometry1, typename Geometry2>
  387. struct touches
  388. <
  389. Geometry1, Geometry2,
  390. geometry_collection_tag, geometry_collection_tag,
  391. geometry_collection_tag, geometry_collection_tag,
  392. false
  393. >
  394. : detail::touches::gc_gc
  395. {};
  396. template <typename Geometry1, typename Geometry2, typename Tag1, typename CastedTag1>
  397. struct touches
  398. <
  399. Geometry1, Geometry2,
  400. Tag1, geometry_collection_tag,
  401. CastedTag1, geometry_collection_tag,
  402. false
  403. >
  404. : detail::touches::notgc_gc
  405. {};
  406. template <typename Geometry1, typename Geometry2, typename Tag2, typename CastedTag2>
  407. struct touches
  408. <
  409. Geometry1, Geometry2,
  410. geometry_collection_tag, Tag2,
  411. geometry_collection_tag, CastedTag2,
  412. false
  413. >
  414. : detail::touches::gc_notgc
  415. {};
  416. } // namespace dispatch
  417. #endif // DOXYGEN_NO_DISPATCH
  418. namespace resolve_dynamic
  419. {
  420. template <typename Geometry, typename Tag>
  421. struct self_touches
  422. {
  423. static bool apply(Geometry const& geometry)
  424. {
  425. concepts::check<Geometry const>();
  426. typedef typename strategies::relate::services::default_strategy
  427. <
  428. Geometry, Geometry
  429. >::type strategy_type;
  430. typedef typename geometry::point_type<Geometry>::type point_type;
  431. typedef detail::overlay::turn_info<point_type> turn_info;
  432. typedef detail::overlay::get_turn_info
  433. <
  434. detail::overlay::assign_null_policy
  435. > policy_type;
  436. std::deque<turn_info> turns;
  437. detail::touches::areal_interrupt_policy policy;
  438. strategy_type strategy;
  439. // TODO: skip_adjacent should be set to false
  440. detail::self_get_turn_points::get_turns
  441. <
  442. false, policy_type
  443. >::apply(geometry, strategy, detail::no_rescale_policy(),
  444. turns, policy, 0, true);
  445. return policy.result();
  446. }
  447. };
  448. } // namespace resolve_dynamic
  449. }} // namespace boost::geometry
  450. #endif // BOOST_GEOMETRY_ALGORITHMS_DETAIL_TOUCHES_IMPLEMENTATION_HPP