touches.hpp 17 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587
  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.
  7. // Modifications copyright (c) 2013-2015, 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_TOUCHES_HPP
  15. #define BOOST_GEOMETRY_ALGORITHMS_TOUCHES_HPP
  16. #include <deque>
  17. #include <boost/variant/apply_visitor.hpp>
  18. #include <boost/variant/static_visitor.hpp>
  19. #include <boost/variant/variant_fwd.hpp>
  20. #include <boost/geometry/geometries/concepts/check.hpp>
  21. #include <boost/geometry/algorithms/detail/for_each_range.hpp>
  22. #include <boost/geometry/algorithms/detail/overlay/overlay.hpp>
  23. #include <boost/geometry/algorithms/detail/overlay/self_turn_points.hpp>
  24. #include <boost/geometry/algorithms/disjoint.hpp>
  25. #include <boost/geometry/algorithms/intersects.hpp>
  26. #include <boost/geometry/algorithms/num_geometries.hpp>
  27. #include <boost/geometry/algorithms/detail/sub_range.hpp>
  28. #include <boost/geometry/policies/robustness/no_rescale_policy.hpp>
  29. #include <boost/geometry/algorithms/relate.hpp>
  30. #include <boost/geometry/algorithms/detail/relate/relate_impl.hpp>
  31. namespace boost { namespace geometry
  32. {
  33. #ifndef DOXYGEN_NO_DETAIL
  34. namespace detail { namespace touches
  35. {
  36. // Box/Box
  37. template
  38. <
  39. std::size_t Dimension,
  40. std::size_t DimensionCount
  41. >
  42. struct box_box_loop
  43. {
  44. template <typename Box1, typename Box2>
  45. static inline bool apply(Box1 const& b1, Box2 const& b2, bool & touch)
  46. {
  47. typedef typename coordinate_type<Box1>::type coordinate_type1;
  48. typedef typename coordinate_type<Box2>::type coordinate_type2;
  49. coordinate_type1 const& min1 = get<min_corner, Dimension>(b1);
  50. coordinate_type1 const& max1 = get<max_corner, Dimension>(b1);
  51. coordinate_type2 const& min2 = get<min_corner, Dimension>(b2);
  52. coordinate_type2 const& max2 = get<max_corner, Dimension>(b2);
  53. // TODO assert or exception?
  54. //BOOST_GEOMETRY_ASSERT(min1 <= max1 && min2 <= max2);
  55. if (max1 < min2 || max2 < min1)
  56. {
  57. return false;
  58. }
  59. if (max1 == min2 || max2 == min1)
  60. {
  61. touch = true;
  62. }
  63. return box_box_loop
  64. <
  65. Dimension + 1,
  66. DimensionCount
  67. >::apply(b1, b2, touch);
  68. }
  69. };
  70. template
  71. <
  72. std::size_t DimensionCount
  73. >
  74. struct box_box_loop<DimensionCount, DimensionCount>
  75. {
  76. template <typename Box1, typename Box2>
  77. static inline bool apply(Box1 const& , Box2 const&, bool &)
  78. {
  79. return true;
  80. }
  81. };
  82. struct box_box
  83. {
  84. template <typename Box1, typename Box2>
  85. static inline bool apply(Box1 const& b1, Box2 const& b2)
  86. {
  87. BOOST_STATIC_ASSERT((boost::is_same
  88. <
  89. typename geometry::coordinate_system<Box1>::type,
  90. typename geometry::coordinate_system<Box2>::type
  91. >::value
  92. ));
  93. assert_dimension_equal<Box1, Box2>();
  94. bool touches = false;
  95. bool ok = box_box_loop
  96. <
  97. 0,
  98. dimension<Box1>::type::value
  99. >::apply(b1, b2, touches);
  100. return ok && touches;
  101. }
  102. };
  103. // Areal/Areal
  104. struct areal_interrupt_policy
  105. {
  106. static bool const enabled = true;
  107. bool found_touch;
  108. bool found_not_touch;
  109. // dummy variable required by self_get_turn_points::get_turns
  110. static bool const has_intersections = false;
  111. inline bool result()
  112. {
  113. return found_touch && !found_not_touch;
  114. }
  115. inline areal_interrupt_policy()
  116. : found_touch(false), found_not_touch(false)
  117. {}
  118. template <typename Range>
  119. inline bool apply(Range const& range)
  120. {
  121. // if already rejected (temp workaround?)
  122. if ( found_not_touch )
  123. return true;
  124. typedef typename boost::range_iterator<Range const>::type iterator;
  125. for ( iterator it = boost::begin(range) ; it != boost::end(range) ; ++it )
  126. {
  127. if ( it->has(overlay::operation_intersection) )
  128. {
  129. found_not_touch = true;
  130. return true;
  131. }
  132. switch(it->method)
  133. {
  134. case overlay::method_crosses:
  135. found_not_touch = true;
  136. return true;
  137. case overlay::method_equal:
  138. // Segment spatially equal means: at the right side
  139. // the polygon internally overlaps. So return false.
  140. found_not_touch = true;
  141. return true;
  142. case overlay::method_touch:
  143. case overlay::method_touch_interior:
  144. case overlay::method_collinear:
  145. if ( ok_for_touch(*it) )
  146. {
  147. found_touch = true;
  148. }
  149. else
  150. {
  151. found_not_touch = true;
  152. return true;
  153. }
  154. break;
  155. case overlay::method_none :
  156. case overlay::method_disjoint :
  157. case overlay::method_error :
  158. break;
  159. }
  160. }
  161. return false;
  162. }
  163. template <typename Turn>
  164. inline bool ok_for_touch(Turn const& turn)
  165. {
  166. return turn.both(overlay::operation_union)
  167. || turn.both(overlay::operation_blocked)
  168. || turn.combination(overlay::operation_union, overlay::operation_blocked)
  169. ;
  170. }
  171. };
  172. template<typename Geometry>
  173. struct check_each_ring_for_within
  174. {
  175. bool has_within;
  176. Geometry const& m_geometry;
  177. inline check_each_ring_for_within(Geometry const& g)
  178. : has_within(false)
  179. , m_geometry(g)
  180. {}
  181. template <typename Range>
  182. inline void apply(Range const& range)
  183. {
  184. typename geometry::point_type<Range>::type p;
  185. geometry::point_on_border(p, range);
  186. if ( !has_within && geometry::within(p, m_geometry) )
  187. {
  188. has_within = true;
  189. }
  190. }
  191. };
  192. template <typename FirstGeometry, typename SecondGeometry>
  193. inline bool rings_containing(FirstGeometry const& geometry1,
  194. SecondGeometry const& geometry2)
  195. {
  196. check_each_ring_for_within<FirstGeometry> checker(geometry1);
  197. geometry::detail::for_each_range(geometry2, checker);
  198. return checker.has_within;
  199. }
  200. template <typename Geometry1, typename Geometry2>
  201. struct areal_areal
  202. {
  203. static inline
  204. bool apply(Geometry1 const& geometry1, Geometry2 const& geometry2)
  205. {
  206. typedef detail::no_rescale_policy rescale_policy_type;
  207. typedef typename geometry::point_type<Geometry1>::type point_type;
  208. typedef detail::overlay::turn_info
  209. <
  210. point_type,
  211. typename segment_ratio_type<point_type, rescale_policy_type>::type
  212. > turn_info;
  213. std::deque<turn_info> turns;
  214. detail::touches::areal_interrupt_policy policy;
  215. rescale_policy_type robust_policy;
  216. boost::geometry::get_turns
  217. <
  218. detail::overlay::do_reverse<geometry::point_order<Geometry1>::value>::value,
  219. detail::overlay::do_reverse<geometry::point_order<Geometry2>::value>::value,
  220. detail::overlay::assign_null_policy
  221. >(geometry1, geometry2, robust_policy, turns, policy);
  222. return policy.result()
  223. && ! geometry::detail::touches::rings_containing(geometry1, geometry2)
  224. && ! geometry::detail::touches::rings_containing(geometry2, geometry1);
  225. }
  226. };
  227. // P/*
  228. struct use_point_in_geometry
  229. {
  230. template <typename Point, typename Geometry>
  231. static inline bool apply(Point const& point, Geometry const& geometry)
  232. {
  233. return detail::within::point_in_geometry(point, geometry) == 0;
  234. }
  235. };
  236. }}
  237. #endif // DOXYGEN_NO_DETAIL
  238. #ifndef DOXYGEN_NO_DISPATCH
  239. namespace dispatch {
  240. // TODO: Since CastedTags are used is Reverse needed?
  241. template
  242. <
  243. typename Geometry1, typename Geometry2,
  244. typename Tag1 = typename tag<Geometry1>::type,
  245. typename Tag2 = typename tag<Geometry2>::type,
  246. typename CastedTag1 = typename tag_cast<Tag1, pointlike_tag, linear_tag, areal_tag>::type,
  247. typename CastedTag2 = typename tag_cast<Tag2, pointlike_tag, linear_tag, areal_tag>::type,
  248. bool Reverse = reverse_dispatch<Geometry1, Geometry2>::type::value
  249. >
  250. struct touches
  251. : not_implemented<Tag1, Tag2>
  252. {};
  253. // If reversal is needed, perform it
  254. template
  255. <
  256. typename Geometry1, typename Geometry2,
  257. typename Tag1, typename Tag2,
  258. typename CastedTag1, typename CastedTag2
  259. >
  260. struct touches<Geometry1, Geometry2, Tag1, Tag2, CastedTag1, CastedTag2, true>
  261. : touches<Geometry2, Geometry1, Tag2, Tag1, CastedTag2, CastedTag1, false>
  262. {
  263. static inline bool apply(Geometry1 const& g1, Geometry2 const& g2)
  264. {
  265. return touches<Geometry2, Geometry1>::apply(g2, g1);
  266. }
  267. };
  268. // P/P
  269. template <typename Geometry1, typename Geometry2, typename Tag1, typename Tag2>
  270. struct touches<Geometry1, Geometry2, Tag1, Tag2, pointlike_tag, pointlike_tag, false>
  271. {
  272. static inline bool apply(Geometry1 const& , Geometry2 const& )
  273. {
  274. return false;
  275. }
  276. };
  277. // P/*
  278. template <typename Point, typename Geometry, typename Tag2, typename CastedTag2>
  279. struct touches<Point, Geometry, point_tag, Tag2, pointlike_tag, CastedTag2, false>
  280. : detail::touches::use_point_in_geometry
  281. {};
  282. // TODO: support touches(MPt, Linear/Areal)
  283. // Box/Box
  284. template <typename Box1, typename Box2, typename CastedTag1, typename CastedTag2>
  285. struct touches<Box1, Box2, box_tag, box_tag, CastedTag1, CastedTag2, false>
  286. : detail::touches::box_box
  287. {};
  288. template <typename Box1, typename Box2>
  289. struct touches<Box1, Box2, box_tag, box_tag, areal_tag, areal_tag, false>
  290. : detail::touches::box_box
  291. {};
  292. // L/L
  293. template <typename Linear1, typename Linear2, typename Tag1, typename Tag2>
  294. struct touches<Linear1, Linear2, Tag1, Tag2, linear_tag, linear_tag, false>
  295. : detail::relate::relate_impl
  296. <
  297. detail::de9im::static_mask_touches_type,
  298. Linear1,
  299. Linear2
  300. >
  301. {};
  302. // L/A
  303. template <typename Linear, typename Areal, typename Tag1, typename Tag2>
  304. struct touches<Linear, Areal, Tag1, Tag2, linear_tag, areal_tag, false>
  305. : detail::relate::relate_impl
  306. <
  307. detail::de9im::static_mask_touches_type,
  308. Linear,
  309. Areal
  310. >
  311. {};
  312. // A/L
  313. template <typename Linear, typename Areal, typename Tag1, typename Tag2>
  314. struct touches<Linear, Areal, Tag1, Tag2, linear_tag, areal_tag, true>
  315. : detail::relate::relate_impl
  316. <
  317. detail::de9im::static_mask_touches_type,
  318. Areal,
  319. Linear
  320. >
  321. {};
  322. // A/A
  323. template <typename Areal1, typename Areal2, typename Tag1, typename Tag2>
  324. struct touches<Areal1, Areal2, Tag1, Tag2, areal_tag, areal_tag, false>
  325. : detail::relate::relate_impl
  326. <
  327. detail::de9im::static_mask_touches_type,
  328. Areal1,
  329. Areal2
  330. >
  331. {};
  332. template <typename Areal1, typename Areal2>
  333. struct touches<Areal1, Areal2, ring_tag, ring_tag, areal_tag, areal_tag, false>
  334. : detail::touches::areal_areal<Areal1, Areal2>
  335. {};
  336. } // namespace dispatch
  337. #endif // DOXYGEN_NO_DISPATCH
  338. namespace resolve_variant {
  339. template <typename Geometry1, typename Geometry2>
  340. struct touches
  341. {
  342. static bool apply(Geometry1 const& geometry1, Geometry2 const& geometry2)
  343. {
  344. concept::check<Geometry1 const>();
  345. concept::check<Geometry2 const>();
  346. return dispatch::touches<Geometry1, Geometry2>
  347. ::apply(geometry1, geometry2);
  348. }
  349. };
  350. template <BOOST_VARIANT_ENUM_PARAMS(typename T), typename Geometry2>
  351. struct touches<boost::variant<BOOST_VARIANT_ENUM_PARAMS(T)>, Geometry2>
  352. {
  353. struct visitor: boost::static_visitor<bool>
  354. {
  355. Geometry2 const& m_geometry2;
  356. visitor(Geometry2 const& geometry2): m_geometry2(geometry2) {}
  357. template <typename Geometry1>
  358. bool operator()(Geometry1 const& geometry1) const
  359. {
  360. return touches<Geometry1, Geometry2>::apply(geometry1, m_geometry2);
  361. }
  362. };
  363. static inline bool
  364. apply(boost::variant<BOOST_VARIANT_ENUM_PARAMS(T)> const& geometry1,
  365. Geometry2 const& geometry2)
  366. {
  367. return boost::apply_visitor(visitor(geometry2), geometry1);
  368. }
  369. };
  370. template <typename Geometry1, BOOST_VARIANT_ENUM_PARAMS(typename T)>
  371. struct touches<Geometry1, boost::variant<BOOST_VARIANT_ENUM_PARAMS(T)> >
  372. {
  373. struct visitor: boost::static_visitor<bool>
  374. {
  375. Geometry1 const& m_geometry1;
  376. visitor(Geometry1 const& geometry1): m_geometry1(geometry1) {}
  377. template <typename Geometry2>
  378. bool operator()(Geometry2 const& geometry2) const
  379. {
  380. return touches<Geometry1, Geometry2>::apply(m_geometry1, geometry2);
  381. }
  382. };
  383. static inline bool
  384. apply(Geometry1 const& geometry1,
  385. boost::variant<BOOST_VARIANT_ENUM_PARAMS(T)> const& geometry2)
  386. {
  387. return boost::apply_visitor(visitor(geometry1), geometry2);
  388. }
  389. };
  390. template <BOOST_VARIANT_ENUM_PARAMS(typename T1),
  391. BOOST_VARIANT_ENUM_PARAMS(typename T2)>
  392. struct touches<boost::variant<BOOST_VARIANT_ENUM_PARAMS(T1)>,
  393. boost::variant<BOOST_VARIANT_ENUM_PARAMS(T2)> >
  394. {
  395. struct visitor: boost::static_visitor<bool>
  396. {
  397. template <typename Geometry1, typename Geometry2>
  398. bool operator()(Geometry1 const& geometry1,
  399. Geometry2 const& geometry2) const
  400. {
  401. return touches<Geometry1, Geometry2>::apply(geometry1, geometry2);
  402. }
  403. };
  404. static inline bool
  405. apply(boost::variant<BOOST_VARIANT_ENUM_PARAMS(T1)> const& geometry1,
  406. boost::variant<BOOST_VARIANT_ENUM_PARAMS(T2)> const& geometry2)
  407. {
  408. return boost::apply_visitor(visitor(), geometry1, geometry2);
  409. }
  410. };
  411. template <typename Geometry>
  412. struct self_touches
  413. {
  414. static bool apply(Geometry const& geometry)
  415. {
  416. concept::check<Geometry const>();
  417. typedef detail::no_rescale_policy rescale_policy_type;
  418. typedef typename geometry::point_type<Geometry>::type point_type;
  419. typedef detail::overlay::turn_info
  420. <
  421. point_type,
  422. typename segment_ratio_type<point_type, rescale_policy_type>::type
  423. > turn_info;
  424. typedef detail::overlay::get_turn_info
  425. <
  426. detail::overlay::assign_null_policy
  427. > policy_type;
  428. std::deque<turn_info> turns;
  429. detail::touches::areal_interrupt_policy policy;
  430. rescale_policy_type robust_policy;
  431. detail::self_get_turn_points::get_turns
  432. <
  433. policy_type
  434. >::apply(geometry, robust_policy, turns, policy);
  435. return policy.result();
  436. }
  437. };
  438. template <BOOST_VARIANT_ENUM_PARAMS(typename T)>
  439. struct self_touches<boost::variant<BOOST_VARIANT_ENUM_PARAMS(T)> >
  440. {
  441. struct visitor: boost::static_visitor<bool>
  442. {
  443. template <typename Geometry>
  444. bool operator()(Geometry const& geometry) const
  445. {
  446. return self_touches<Geometry>::apply(geometry);
  447. }
  448. };
  449. static inline bool
  450. apply(boost::variant<BOOST_VARIANT_ENUM_PARAMS(T)> const& geometry)
  451. {
  452. return boost::apply_visitor(visitor(), geometry);
  453. }
  454. };
  455. } // namespace resolve_variant
  456. /*!
  457. \brief \brief_check{has at least one touching point (self-tangency)}
  458. \note This function can be called for one geometry (self-tangency) and
  459. also for two geometries (touch)
  460. \ingroup touches
  461. \tparam Geometry \tparam_geometry
  462. \param geometry \param_geometry
  463. \return \return_check{is self-touching}
  464. \qbk{distinguish,one geometry}
  465. \qbk{[def __one_parameter__]}
  466. \qbk{[include reference/algorithms/touches.qbk]}
  467. */
  468. template <typename Geometry>
  469. inline bool touches(Geometry const& geometry)
  470. {
  471. return resolve_variant::self_touches<Geometry>::apply(geometry);
  472. }
  473. /*!
  474. \brief \brief_check2{have at least one touching point (tangent - non overlapping)}
  475. \ingroup touches
  476. \tparam Geometry1 \tparam_geometry
  477. \tparam Geometry2 \tparam_geometry
  478. \param geometry1 \param_geometry
  479. \param geometry2 \param_geometry
  480. \return \return_check2{touch each other}
  481. \qbk{distinguish,two geometries}
  482. \qbk{[include reference/algorithms/touches.qbk]}
  483. */
  484. template <typename Geometry1, typename Geometry2>
  485. inline bool touches(Geometry1 const& geometry1, Geometry2 const& geometry2)
  486. {
  487. return resolve_variant::touches<Geometry1, Geometry2>::apply(geometry1, geometry2);
  488. }
  489. }} // namespace boost::geometry
  490. #endif // BOOST_GEOMETRY_ALGORITHMS_TOUCHES_HPP