implementation.hpp 14 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462
  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.
  7. // Modifications copyright (c) 2013-2017, 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 detail::no_rescale_policy rescale_policy_type;
  218. typedef typename geometry::point_type<Geometry1>::type point_type;
  219. typedef detail::overlay::turn_info
  220. <
  221. point_type,
  222. typename segment_ratio_type<point_type, rescale_policy_type>::type
  223. > turn_info;
  224. std::deque<turn_info> turns;
  225. detail::touches::areal_interrupt_policy policy;
  226. rescale_policy_type robust_policy;
  227. boost::geometry::get_turns
  228. <
  229. detail::overlay::do_reverse<geometry::point_order<Geometry1>::value>::value,
  230. detail::overlay::do_reverse<geometry::point_order<Geometry2>::value>::value,
  231. detail::overlay::assign_null_policy
  232. >(geometry1, geometry2, strategy, robust_policy, turns, policy);
  233. return policy.result()
  234. && ! geometry::detail::touches::rings_containing(geometry1, geometry2, strategy)
  235. && ! geometry::detail::touches::rings_containing(geometry2, geometry1, strategy);
  236. }
  237. };
  238. // P/*
  239. struct use_point_in_geometry
  240. {
  241. template <typename Point, typename Geometry, typename Strategy>
  242. static inline bool apply(Point const& point, Geometry const& geometry, Strategy const& strategy)
  243. {
  244. return detail::within::point_in_geometry(point, geometry, strategy) == 0;
  245. }
  246. };
  247. }}
  248. #endif // DOXYGEN_NO_DETAIL
  249. #ifndef DOXYGEN_NO_DISPATCH
  250. namespace dispatch {
  251. // P/P
  252. template <typename Geometry1, typename Geometry2, typename Tag2>
  253. struct touches<Geometry1, Geometry2, point_tag, Tag2, pointlike_tag, pointlike_tag, false>
  254. {
  255. template <typename Strategy>
  256. static inline bool apply(Geometry1 const& , Geometry2 const& , Strategy const&)
  257. {
  258. return false;
  259. }
  260. };
  261. template <typename Geometry1, typename Geometry2, typename Tag2>
  262. struct touches<Geometry1, Geometry2, multi_point_tag, Tag2, pointlike_tag, pointlike_tag, false>
  263. {
  264. template <typename Strategy>
  265. static inline bool apply(Geometry1 const&, Geometry2 const&, Strategy const&)
  266. {
  267. return false;
  268. }
  269. };
  270. // P/*
  271. template <typename Point, typename Geometry, typename Tag2, typename CastedTag2>
  272. struct touches<Point, Geometry, point_tag, Tag2, pointlike_tag, CastedTag2, false>
  273. : detail::touches::use_point_in_geometry
  274. {};
  275. template <typename MultiPoint, typename MultiGeometry, typename Tag2, typename CastedTag2>
  276. struct touches<MultiPoint, MultiGeometry, multi_point_tag, Tag2, pointlike_tag, CastedTag2, false>
  277. : detail::relate::relate_impl
  278. <
  279. detail::de9im::static_mask_touches_type,
  280. MultiPoint,
  281. MultiGeometry
  282. >
  283. {};
  284. template <typename Geometry, typename MultiPoint, typename Tag1, typename CastedTag1>
  285. struct touches<Geometry, MultiPoint, Tag1, multi_point_tag, CastedTag1, pointlike_tag, false>
  286. : detail::relate::relate_impl
  287. <
  288. detail::de9im::static_mask_touches_type,
  289. Geometry,
  290. MultiPoint
  291. >
  292. {};
  293. // Box/Box
  294. template <typename Box1, typename Box2, typename CastedTag1, typename CastedTag2>
  295. struct touches<Box1, Box2, box_tag, box_tag, CastedTag1, CastedTag2, false>
  296. : detail::touches::box_box
  297. {};
  298. template <typename Box1, typename Box2>
  299. struct touches<Box1, Box2, box_tag, box_tag, areal_tag, areal_tag, false>
  300. : detail::touches::box_box
  301. {};
  302. // L/L
  303. template <typename Linear1, typename Linear2, typename Tag1, typename Tag2>
  304. struct touches<Linear1, Linear2, Tag1, Tag2, linear_tag, linear_tag, false>
  305. : detail::relate::relate_impl
  306. <
  307. detail::de9im::static_mask_touches_type,
  308. Linear1,
  309. Linear2
  310. >
  311. {};
  312. // L/A
  313. template <typename Linear, typename Areal, typename Tag1, typename Tag2>
  314. struct touches<Linear, Areal, Tag1, Tag2, linear_tag, areal_tag, false>
  315. : detail::relate::relate_impl
  316. <
  317. detail::de9im::static_mask_touches_type,
  318. Linear,
  319. Areal
  320. >
  321. {};
  322. // A/L
  323. template <typename Linear, typename Areal, typename Tag1, typename Tag2>
  324. struct touches<Areal, Linear, Tag1, Tag2, areal_tag, linear_tag, false>
  325. : detail::relate::relate_impl
  326. <
  327. detail::de9im::static_mask_touches_type,
  328. Areal,
  329. Linear
  330. >
  331. {};
  332. // A/A
  333. template <typename Areal1, typename Areal2, typename Tag1, typename Tag2>
  334. struct touches<Areal1, Areal2, Tag1, Tag2, areal_tag, areal_tag, false>
  335. : detail::relate::relate_impl
  336. <
  337. detail::de9im::static_mask_touches_type,
  338. Areal1,
  339. Areal2
  340. >
  341. {};
  342. template <typename Areal1, typename Areal2>
  343. struct touches<Areal1, Areal2, ring_tag, ring_tag, areal_tag, areal_tag, false>
  344. : detail::touches::areal_areal<Areal1, Areal2>
  345. {};
  346. } // namespace dispatch
  347. #endif // DOXYGEN_NO_DISPATCH
  348. namespace resolve_variant
  349. {
  350. template <typename Geometry>
  351. struct self_touches
  352. {
  353. static bool apply(Geometry const& geometry)
  354. {
  355. concepts::check<Geometry const>();
  356. typedef typename strategy::relate::services::default_strategy
  357. <
  358. Geometry, Geometry
  359. >::type strategy_type;
  360. typedef detail::no_rescale_policy rescale_policy_type;
  361. typedef typename geometry::point_type<Geometry>::type point_type;
  362. typedef detail::overlay::turn_info
  363. <
  364. point_type,
  365. typename segment_ratio_type<point_type, rescale_policy_type>::type
  366. > turn_info;
  367. typedef detail::overlay::get_turn_info
  368. <
  369. detail::overlay::assign_null_policy
  370. > policy_type;
  371. std::deque<turn_info> turns;
  372. detail::touches::areal_interrupt_policy policy;
  373. strategy_type strategy;
  374. rescale_policy_type robust_policy;
  375. // TODO: skip_adjacent should be set to false
  376. detail::self_get_turn_points::get_turns
  377. <
  378. false, policy_type
  379. >::apply(geometry, strategy, robust_policy, turns, policy, 0, true);
  380. return policy.result();
  381. }
  382. };
  383. }
  384. }} // namespace boost::geometry
  385. #endif // BOOST_GEOMETRY_ALGORITHMS_DETAIL_TOUCHES_IMPLEMENTATION_HPP