select_rings.hpp 12 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372
  1. // Boost.Geometry (aka GGL, Generic Geometry Library)
  2. // Copyright (c) 2007-2014 Barend Gehrels, Amsterdam, the Netherlands.
  3. // Copyright (c) 2014 Adam Wulkiewicz, Lodz, Poland.
  4. // This file was modified by Oracle on 2017.
  5. // Modifications copyright (c) 2017 Oracle and/or its affiliates.
  6. // Contributed and/or modified by Adam Wulkiewicz, on behalf of Oracle
  7. // Use, modification and distribution is subject to the Boost Software License,
  8. // Version 1.0. (See accompanying file LICENSE_1_0.txt or copy at
  9. // http://www.boost.org/LICENSE_1_0.txt)
  10. #ifndef BOOST_GEOMETRY_ALGORITHMS_DETAIL_OVERLAY_SELECT_RINGS_HPP
  11. #define BOOST_GEOMETRY_ALGORITHMS_DETAIL_OVERLAY_SELECT_RINGS_HPP
  12. #include <map>
  13. #include <boost/range.hpp>
  14. #include <boost/geometry/core/tags.hpp>
  15. #include <boost/geometry/algorithms/covered_by.hpp>
  16. #include <boost/geometry/algorithms/detail/interior_iterator.hpp>
  17. #include <boost/geometry/algorithms/detail/ring_identifier.hpp>
  18. #include <boost/geometry/algorithms/detail/overlay/range_in_geometry.hpp>
  19. #include <boost/geometry/algorithms/detail/overlay/ring_properties.hpp>
  20. #include <boost/geometry/algorithms/detail/overlay/overlay_type.hpp>
  21. namespace boost { namespace geometry
  22. {
  23. #ifndef DOXYGEN_NO_DETAIL
  24. namespace detail { namespace overlay
  25. {
  26. struct ring_turn_info
  27. {
  28. bool has_traversed_turn;
  29. bool has_blocked_turn;
  30. bool within_other;
  31. ring_turn_info()
  32. : has_traversed_turn(false)
  33. , has_blocked_turn(false)
  34. , within_other(false)
  35. {}
  36. };
  37. namespace dispatch
  38. {
  39. template <typename Tag, typename Geometry>
  40. struct select_rings
  41. {};
  42. template <typename Box>
  43. struct select_rings<box_tag, Box>
  44. {
  45. template <typename Geometry, typename RingPropertyMap, typename AreaStrategy>
  46. static inline void apply(Box const& box, Geometry const& ,
  47. ring_identifier const& id, RingPropertyMap& ring_properties,
  48. AreaStrategy const& strategy)
  49. {
  50. ring_properties[id] = typename RingPropertyMap::mapped_type(box, strategy);
  51. }
  52. template <typename RingPropertyMap, typename AreaStrategy>
  53. static inline void apply(Box const& box,
  54. ring_identifier const& id, RingPropertyMap& ring_properties,
  55. AreaStrategy const& strategy)
  56. {
  57. ring_properties[id] = typename RingPropertyMap::mapped_type(box, strategy);
  58. }
  59. };
  60. template <typename Ring>
  61. struct select_rings<ring_tag, Ring>
  62. {
  63. template <typename Geometry, typename RingPropertyMap, typename AreaStrategy>
  64. static inline void apply(Ring const& ring, Geometry const& ,
  65. ring_identifier const& id, RingPropertyMap& ring_properties,
  66. AreaStrategy const& strategy)
  67. {
  68. if (boost::size(ring) > 0)
  69. {
  70. ring_properties[id] = typename RingPropertyMap::mapped_type(ring, strategy);
  71. }
  72. }
  73. template <typename RingPropertyMap, typename AreaStrategy>
  74. static inline void apply(Ring const& ring,
  75. ring_identifier const& id, RingPropertyMap& ring_properties,
  76. AreaStrategy const& strategy)
  77. {
  78. if (boost::size(ring) > 0)
  79. {
  80. ring_properties[id] = typename RingPropertyMap::mapped_type(ring, strategy);
  81. }
  82. }
  83. };
  84. template <typename Polygon>
  85. struct select_rings<polygon_tag, Polygon>
  86. {
  87. template <typename Geometry, typename RingPropertyMap, typename AreaStrategy>
  88. static inline void apply(Polygon const& polygon, Geometry const& geometry,
  89. ring_identifier id, RingPropertyMap& ring_properties,
  90. AreaStrategy const& strategy)
  91. {
  92. typedef typename geometry::ring_type<Polygon>::type ring_type;
  93. typedef select_rings<ring_tag, ring_type> per_ring;
  94. per_ring::apply(exterior_ring(polygon), geometry, id, ring_properties, strategy);
  95. typename interior_return_type<Polygon const>::type
  96. rings = interior_rings(polygon);
  97. for (typename detail::interior_iterator<Polygon const>::type
  98. it = boost::begin(rings); it != boost::end(rings); ++it)
  99. {
  100. id.ring_index++;
  101. per_ring::apply(*it, geometry, id, ring_properties, strategy);
  102. }
  103. }
  104. template <typename RingPropertyMap, typename AreaStrategy>
  105. static inline void apply(Polygon const& polygon,
  106. ring_identifier id, RingPropertyMap& ring_properties,
  107. AreaStrategy const& strategy)
  108. {
  109. typedef typename geometry::ring_type<Polygon>::type ring_type;
  110. typedef select_rings<ring_tag, ring_type> per_ring;
  111. per_ring::apply(exterior_ring(polygon), id, ring_properties, strategy);
  112. typename interior_return_type<Polygon const>::type
  113. rings = interior_rings(polygon);
  114. for (typename detail::interior_iterator<Polygon const>::type
  115. it = boost::begin(rings); it != boost::end(rings); ++it)
  116. {
  117. id.ring_index++;
  118. per_ring::apply(*it, id, ring_properties, strategy);
  119. }
  120. }
  121. };
  122. template <typename Multi>
  123. struct select_rings<multi_polygon_tag, Multi>
  124. {
  125. template <typename Geometry, typename RingPropertyMap, typename AreaStrategy>
  126. static inline void apply(Multi const& multi, Geometry const& geometry,
  127. ring_identifier id, RingPropertyMap& ring_properties,
  128. AreaStrategy const& strategy)
  129. {
  130. typedef typename boost::range_iterator
  131. <
  132. Multi const
  133. >::type iterator_type;
  134. typedef select_rings<polygon_tag, typename boost::range_value<Multi>::type> per_polygon;
  135. id.multi_index = 0;
  136. for (iterator_type it = boost::begin(multi); it != boost::end(multi); ++it)
  137. {
  138. id.ring_index = -1;
  139. per_polygon::apply(*it, geometry, id, ring_properties, strategy);
  140. id.multi_index++;
  141. }
  142. }
  143. };
  144. } // namespace dispatch
  145. template<overlay_type OverlayType>
  146. struct decide
  147. {
  148. // Default implementation (union, inflate, deflate, dissolve)
  149. static bool include(ring_identifier const& , ring_turn_info const& info)
  150. {
  151. return ! info.within_other;
  152. }
  153. static bool reversed(ring_identifier const& , ring_turn_info const& )
  154. {
  155. return false;
  156. }
  157. };
  158. template<>
  159. struct decide<overlay_difference>
  160. {
  161. static bool include(ring_identifier const& id, ring_turn_info const& info)
  162. {
  163. // Difference: A - B
  164. // If this is A (source_index=0), then the ring is inside B
  165. // If this is B (source_index=1), then the ring is NOT inside A
  166. // If this is A and the ring is within the other geometry,
  167. // then we should NOT include it.
  168. // If this is B then we SHOULD include it.
  169. return id.source_index == 0
  170. ? ! info.within_other
  171. : info.within_other;
  172. }
  173. static bool reversed(ring_identifier const& id, ring_turn_info const& info)
  174. {
  175. // Difference: A - B
  176. // If this is B, and the ring is included, it should be reversed afterwards
  177. return id.source_index == 1 && include(id, info);
  178. }
  179. };
  180. template<>
  181. struct decide<overlay_intersection>
  182. {
  183. static bool include(ring_identifier const& , ring_turn_info const& info)
  184. {
  185. return info.within_other;
  186. }
  187. static bool reversed(ring_identifier const& , ring_turn_info const& )
  188. {
  189. return false;
  190. }
  191. };
  192. template
  193. <
  194. overlay_type OverlayType,
  195. typename Geometry1,
  196. typename Geometry2,
  197. typename TurnInfoMap,
  198. typename RingPropertyMap,
  199. typename Strategy
  200. >
  201. inline void update_ring_selection(Geometry1 const& geometry1,
  202. Geometry2 const& geometry2,
  203. TurnInfoMap const& turn_info_map,
  204. RingPropertyMap const& all_ring_properties,
  205. RingPropertyMap& selected_ring_properties,
  206. Strategy const& strategy)
  207. {
  208. selected_ring_properties.clear();
  209. for (typename RingPropertyMap::const_iterator it = boost::begin(all_ring_properties);
  210. it != boost::end(all_ring_properties);
  211. ++it)
  212. {
  213. ring_identifier const& id = it->first;
  214. ring_turn_info info;
  215. typename TurnInfoMap::const_iterator tcit = turn_info_map.find(id);
  216. if (tcit != turn_info_map.end())
  217. {
  218. info = tcit->second; // Copy by value
  219. }
  220. if (info.has_traversed_turn || info.has_blocked_turn)
  221. {
  222. // This turn is traversed or blocked,
  223. // don't include the original ring
  224. continue;
  225. }
  226. // Check if the ring is within the other geometry, by taking
  227. // a point lying on the ring
  228. switch(id.source_index)
  229. {
  230. // within
  231. case 0 :
  232. info.within_other = range_in_geometry(it->second.point,
  233. geometry1, geometry2,
  234. strategy) > 0;
  235. break;
  236. case 1 :
  237. info.within_other = range_in_geometry(it->second.point,
  238. geometry2, geometry1,
  239. strategy) > 0;
  240. break;
  241. }
  242. if (decide<OverlayType>::include(id, info))
  243. {
  244. typename RingPropertyMap::mapped_type properties = it->second; // Copy by value
  245. properties.reversed = decide<OverlayType>::reversed(id, info);
  246. selected_ring_properties[id] = properties;
  247. }
  248. }
  249. }
  250. /*!
  251. \brief The function select_rings select rings based on the overlay-type (union,intersection)
  252. */
  253. template
  254. <
  255. overlay_type OverlayType,
  256. typename Geometry1,
  257. typename Geometry2,
  258. typename RingTurnInfoMap,
  259. typename RingPropertyMap,
  260. typename Strategy
  261. >
  262. inline void select_rings(Geometry1 const& geometry1, Geometry2 const& geometry2,
  263. RingTurnInfoMap const& turn_info_per_ring,
  264. RingPropertyMap& selected_ring_properties,
  265. Strategy const& strategy)
  266. {
  267. typedef typename geometry::tag<Geometry1>::type tag1;
  268. typedef typename geometry::tag<Geometry2>::type tag2;
  269. typedef typename geometry::point_type<Geometry1>::type point1_type;
  270. typedef typename geometry::point_type<Geometry2>::type point2_type;
  271. RingPropertyMap all_ring_properties;
  272. dispatch::select_rings<tag1, Geometry1>::apply(geometry1, geometry2,
  273. ring_identifier(0, -1, -1), all_ring_properties,
  274. strategy.template get_area_strategy<point1_type>());
  275. dispatch::select_rings<tag2, Geometry2>::apply(geometry2, geometry1,
  276. ring_identifier(1, -1, -1), all_ring_properties,
  277. strategy.template get_area_strategy<point2_type>());
  278. update_ring_selection<OverlayType>(geometry1, geometry2, turn_info_per_ring,
  279. all_ring_properties, selected_ring_properties,
  280. strategy);
  281. }
  282. template
  283. <
  284. overlay_type OverlayType,
  285. typename Geometry,
  286. typename RingTurnInfoMap,
  287. typename RingPropertyMap,
  288. typename Strategy
  289. >
  290. inline void select_rings(Geometry const& geometry,
  291. RingTurnInfoMap const& turn_info_per_ring,
  292. RingPropertyMap& selected_ring_properties,
  293. Strategy const& strategy)
  294. {
  295. typedef typename geometry::tag<Geometry>::type tag;
  296. typedef typename geometry::point_type<Geometry>::type point_type;
  297. RingPropertyMap all_ring_properties;
  298. dispatch::select_rings<tag, Geometry>::apply(geometry,
  299. ring_identifier(0, -1, -1), all_ring_properties,
  300. strategy.template get_area_strategy<point_type>());
  301. update_ring_selection<OverlayType>(geometry, geometry, turn_info_per_ring,
  302. all_ring_properties, selected_ring_properties,
  303. strategy);
  304. }
  305. }} // namespace detail::overlay
  306. #endif // DOXYGEN_NO_DETAIL
  307. }} // namespace boost::geometry
  308. #endif // BOOST_GEOMETRY_ALGORITHMS_DETAIL_OVERLAY_SELECT_RINGS_HPP