overlay.hpp 9.5 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316
  1. // Boost.Geometry (aka GGL, Generic Geometry Library)
  2. // Copyright (c) 2007-2012 Barend Gehrels, Amsterdam, the Netherlands.
  3. // Use, modification and distribution is subject to the Boost Software License,
  4. // Version 1.0. (See accompanying file LICENSE_1_0.txt or copy at
  5. // http://www.boost.org/LICENSE_1_0.txt)
  6. #ifndef BOOST_GEOMETRY_ALGORITHMS_DETAIL_OVERLAY_OVERLAY_HPP
  7. #define BOOST_GEOMETRY_ALGORITHMS_DETAIL_OVERLAY_OVERLAY_HPP
  8. #include <deque>
  9. #include <map>
  10. #include <boost/range.hpp>
  11. #include <boost/mpl/assert.hpp>
  12. #include <boost/geometry/algorithms/detail/overlay/calculate_distance_policy.hpp>
  13. #include <boost/geometry/algorithms/detail/overlay/enrich_intersection_points.hpp>
  14. #include <boost/geometry/algorithms/detail/overlay/enrichment_info.hpp>
  15. #include <boost/geometry/algorithms/detail/overlay/get_turns.hpp>
  16. #include <boost/geometry/algorithms/detail/overlay/overlay_type.hpp>
  17. #include <boost/geometry/algorithms/detail/overlay/traverse.hpp>
  18. #include <boost/geometry/algorithms/detail/overlay/traversal_info.hpp>
  19. #include <boost/geometry/algorithms/detail/overlay/turn_info.hpp>
  20. #include <boost/geometry/algorithms/num_points.hpp>
  21. #include <boost/geometry/algorithms/reverse.hpp>
  22. #include <boost/geometry/algorithms/detail/overlay/add_rings.hpp>
  23. #include <boost/geometry/algorithms/detail/overlay/assign_parents.hpp>
  24. #include <boost/geometry/algorithms/detail/overlay/ring_properties.hpp>
  25. #include <boost/geometry/algorithms/detail/overlay/select_rings.hpp>
  26. #ifdef BOOST_GEOMETRY_DEBUG_ASSEMBLE
  27. # include <boost/geometry/io/dsv/write.hpp>
  28. #endif
  29. #ifdef BOOST_GEOMETRY_TIME_OVERLAY
  30. # include <boost/timer.hpp>
  31. #endif
  32. namespace boost { namespace geometry
  33. {
  34. #ifndef DOXYGEN_NO_DETAIL
  35. namespace detail { namespace overlay
  36. {
  37. // Skip for assemble process
  38. template <typename TurnInfo>
  39. inline bool skip(TurnInfo const& turn_info)
  40. {
  41. return (turn_info.discarded || turn_info.both(operation_union))
  42. && ! turn_info.any_blocked()
  43. && ! turn_info.both(operation_intersection)
  44. ;
  45. }
  46. template <typename TurnPoints, typename Map>
  47. inline void map_turns(Map& map, TurnPoints const& turn_points)
  48. {
  49. typedef typename boost::range_value<TurnPoints>::type turn_point_type;
  50. typedef typename turn_point_type::container_type container_type;
  51. int index = 0;
  52. for (typename boost::range_iterator<TurnPoints const>::type
  53. it = boost::begin(turn_points);
  54. it != boost::end(turn_points);
  55. ++it, ++index)
  56. {
  57. if (! skip(*it))
  58. {
  59. int op_index = 0;
  60. for (typename boost::range_iterator<container_type const>::type
  61. op_it = boost::begin(it->operations);
  62. op_it != boost::end(it->operations);
  63. ++op_it, ++op_index)
  64. {
  65. ring_identifier ring_id
  66. (
  67. op_it->seg_id.source_index,
  68. op_it->seg_id.multi_index,
  69. op_it->seg_id.ring_index
  70. );
  71. map[ring_id]++;
  72. }
  73. }
  74. }
  75. }
  76. template
  77. <
  78. typename GeometryOut, overlay_type Direction, bool ReverseOut,
  79. typename Geometry1, typename Geometry2,
  80. typename OutputIterator
  81. >
  82. inline OutputIterator return_if_one_input_is_empty(Geometry1 const& geometry1,
  83. Geometry2 const& geometry2,
  84. OutputIterator out)
  85. {
  86. typedef std::deque
  87. <
  88. typename geometry::ring_type<GeometryOut>::type
  89. > ring_container_type;
  90. typedef ring_properties<typename geometry::point_type<Geometry1>::type> properties;
  91. // Silence warning C4127: conditional expression is constant
  92. #if defined(_MSC_VER)
  93. #pragma warning(push)
  94. #pragma warning(disable : 4127)
  95. #endif
  96. // Union: return either of them
  97. // Intersection: return nothing
  98. // Difference: return first of them
  99. if (Direction == overlay_intersection
  100. || (Direction == overlay_difference
  101. && geometry::num_points(geometry1) == 0))
  102. {
  103. return out;
  104. }
  105. #if defined(_MSC_VER)
  106. #pragma warning(pop)
  107. #endif
  108. std::map<ring_identifier, int> empty;
  109. std::map<ring_identifier, properties> all_of_one_of_them;
  110. select_rings<Direction>(geometry1, geometry2, empty, all_of_one_of_them, false);
  111. ring_container_type rings;
  112. assign_parents(geometry1, geometry2, rings, all_of_one_of_them);
  113. return add_rings<GeometryOut>(all_of_one_of_them, geometry1, geometry2, rings, out);
  114. }
  115. template
  116. <
  117. typename Geometry1, typename Geometry2,
  118. bool Reverse1, bool Reverse2, bool ReverseOut,
  119. typename GeometryOut,
  120. overlay_type Direction
  121. >
  122. struct overlay
  123. {
  124. template <typename OutputIterator, typename Strategy>
  125. static inline OutputIterator apply(
  126. Geometry1 const& geometry1, Geometry2 const& geometry2,
  127. OutputIterator out,
  128. Strategy const& )
  129. {
  130. if (geometry::num_points(geometry1) == 0
  131. && geometry::num_points(geometry2) == 0)
  132. {
  133. return out;
  134. }
  135. if (geometry::num_points(geometry1) == 0
  136. || geometry::num_points(geometry2) == 0)
  137. {
  138. return return_if_one_input_is_empty
  139. <
  140. GeometryOut, Direction, ReverseOut
  141. >(geometry1, geometry2, out);
  142. }
  143. typedef typename geometry::point_type<GeometryOut>::type point_type;
  144. typedef detail::overlay::traversal_turn_info<point_type> turn_info;
  145. typedef std::deque<turn_info> container_type;
  146. typedef std::deque
  147. <
  148. typename geometry::ring_type<GeometryOut>::type
  149. > ring_container_type;
  150. container_type turn_points;
  151. #ifdef BOOST_GEOMETRY_TIME_OVERLAY
  152. boost::timer timer;
  153. #endif
  154. #ifdef BOOST_GEOMETRY_DEBUG_ASSEMBLE
  155. std::cout << "get turns" << std::endl;
  156. #endif
  157. detail::get_turns::no_interrupt_policy policy;
  158. geometry::get_turns
  159. <
  160. Reverse1, Reverse2,
  161. detail::overlay::calculate_distance_policy
  162. >(geometry1, geometry2, turn_points, policy);
  163. #ifdef BOOST_GEOMETRY_TIME_OVERLAY
  164. std::cout << "get_turns: " << timer.elapsed() << std::endl;
  165. #endif
  166. #ifdef BOOST_GEOMETRY_DEBUG_ASSEMBLE
  167. std::cout << "enrich" << std::endl;
  168. #endif
  169. typename Strategy::side_strategy_type side_strategy;
  170. geometry::enrich_intersection_points<Reverse1, Reverse2>(turn_points,
  171. Direction == overlay_union
  172. ? geometry::detail::overlay::operation_union
  173. : geometry::detail::overlay::operation_intersection,
  174. geometry1, geometry2,
  175. side_strategy);
  176. #ifdef BOOST_GEOMETRY_TIME_OVERLAY
  177. std::cout << "enrich_intersection_points: " << timer.elapsed() << std::endl;
  178. #endif
  179. #ifdef BOOST_GEOMETRY_DEBUG_ASSEMBLE
  180. std::cout << "traverse" << std::endl;
  181. #endif
  182. // Traverse through intersection/turn points and create rings of them.
  183. // Note that these rings are always in clockwise order, even in CCW polygons,
  184. // and are marked as "to be reversed" below
  185. ring_container_type rings;
  186. traverse<Reverse1, Reverse2, Geometry1, Geometry2>::apply
  187. (
  188. geometry1, geometry2,
  189. Direction == overlay_union
  190. ? geometry::detail::overlay::operation_union
  191. : geometry::detail::overlay::operation_intersection,
  192. turn_points, rings
  193. );
  194. #ifdef BOOST_GEOMETRY_TIME_OVERLAY
  195. std::cout << "traverse: " << timer.elapsed() << std::endl;
  196. #endif
  197. std::map<ring_identifier, int> map;
  198. map_turns(map, turn_points);
  199. #ifdef BOOST_GEOMETRY_TIME_OVERLAY
  200. std::cout << "map_turns: " << timer.elapsed() << std::endl;
  201. #endif
  202. typedef ring_properties<typename geometry::point_type<GeometryOut>::type> properties;
  203. std::map<ring_identifier, properties> selected;
  204. select_rings<Direction>(geometry1, geometry2, map, selected, ! turn_points.empty());
  205. #ifdef BOOST_GEOMETRY_TIME_OVERLAY
  206. std::cout << "select_rings: " << timer.elapsed() << std::endl;
  207. #endif
  208. // Add rings created during traversal
  209. {
  210. ring_identifier id(2, 0, -1);
  211. for (typename boost::range_iterator<ring_container_type>::type
  212. it = boost::begin(rings);
  213. it != boost::end(rings);
  214. ++it)
  215. {
  216. selected[id] = properties(*it, true);
  217. selected[id].reversed = ReverseOut;
  218. id.multi_index++;
  219. }
  220. }
  221. #ifdef BOOST_GEOMETRY_TIME_OVERLAY
  222. std::cout << "add traversal rings: " << timer.elapsed() << std::endl;
  223. #endif
  224. assign_parents(geometry1, geometry2, rings, selected);
  225. #ifdef BOOST_GEOMETRY_TIME_OVERLAY
  226. std::cout << "assign_parents: " << timer.elapsed() << std::endl;
  227. #endif
  228. return add_rings<GeometryOut>(selected, geometry1, geometry2, rings, out);
  229. }
  230. };
  231. // Metafunction helper for intersection and union
  232. template <order_selector Selector, bool Reverse = false>
  233. struct do_reverse {};
  234. template <>
  235. struct do_reverse<clockwise, false> : boost::false_type {};
  236. template <>
  237. struct do_reverse<clockwise, true> : boost::true_type {};
  238. template <>
  239. struct do_reverse<counterclockwise, false> : boost::true_type {};
  240. template <>
  241. struct do_reverse<counterclockwise, true> : boost::false_type {};
  242. }} // namespace detail::overlay
  243. #endif // DOXYGEN_NO_DETAIL
  244. }} // namespace boost::geometry
  245. #endif // BOOST_GEOMETRY_ALGORITHMS_DETAIL_OVERLAY_OVERLAY_HPP