follow.hpp 12 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416
  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_FOLLOW_HPP
  7. #define BOOST_GEOMETRY_ALGORITHMS_DETAIL_OVERLAY_FOLLOW_HPP
  8. #include <cstddef>
  9. #include <boost/range.hpp>
  10. #include <boost/mpl/assert.hpp>
  11. #include <boost/geometry/algorithms/detail/point_on_border.hpp>
  12. #include <boost/geometry/algorithms/detail/overlay/append_no_duplicates.hpp>
  13. #include <boost/geometry/algorithms/detail/overlay/copy_segments.hpp>
  14. #include <boost/geometry/algorithms/detail/overlay/turn_info.hpp>
  15. #include <boost/geometry/algorithms/covered_by.hpp>
  16. namespace boost { namespace geometry
  17. {
  18. #ifndef DOXYGEN_NO_DETAIL
  19. namespace detail { namespace overlay
  20. {
  21. namespace following
  22. {
  23. template <typename Turn, typename Operation>
  24. static inline bool is_entering(Turn const& /* TODO remove this parameter */, Operation const& op)
  25. {
  26. // (Blocked means: blocked for polygon/polygon intersection, because
  27. // they are reversed. But for polygon/line it is similar to continue)
  28. return op.operation == operation_intersection
  29. || op.operation == operation_continue
  30. || op.operation == operation_blocked
  31. ;
  32. }
  33. template
  34. <
  35. typename Turn,
  36. typename Operation,
  37. typename LineString,
  38. typename Polygon
  39. >
  40. static inline bool last_covered_by(Turn const& turn, Operation const& op,
  41. LineString const& linestring, Polygon const& polygon)
  42. {
  43. // Check any point between the this one and the first IP
  44. typedef typename geometry::point_type<LineString>::type point_type;
  45. point_type point_in_between;
  46. detail::point_on_border::midpoint_helper
  47. <
  48. point_type,
  49. 0, dimension<point_type>::value
  50. >::apply(point_in_between, linestring[op.seg_id.segment_index], turn.point);
  51. return geometry::covered_by(point_in_between, polygon);
  52. }
  53. template
  54. <
  55. typename Turn,
  56. typename Operation,
  57. typename LineString,
  58. typename Polygon
  59. >
  60. static inline bool is_leaving(Turn const& turn, Operation const& op,
  61. bool entered, bool first,
  62. LineString const& linestring, Polygon const& polygon)
  63. {
  64. if (op.operation == operation_union)
  65. {
  66. return entered
  67. || turn.method == method_crosses
  68. || (first && last_covered_by(turn, op, linestring, polygon))
  69. ;
  70. }
  71. return false;
  72. }
  73. template
  74. <
  75. typename Turn,
  76. typename Operation,
  77. typename LineString,
  78. typename Polygon
  79. >
  80. static inline bool is_staying_inside(Turn const& turn, Operation const& op,
  81. bool entered, bool first,
  82. LineString const& linestring, Polygon const& polygon)
  83. {
  84. if (turn.method == method_crosses)
  85. {
  86. // The normal case, this is completely covered with entering/leaving
  87. // so stay out of this time consuming "covered_by"
  88. return false;
  89. }
  90. if (is_entering(turn, op))
  91. {
  92. return entered || (first && last_covered_by(turn, op, linestring, polygon));
  93. }
  94. return false;
  95. }
  96. template
  97. <
  98. typename Turn,
  99. typename Operation,
  100. typename Linestring,
  101. typename Polygon
  102. >
  103. static inline bool was_entered(Turn const& turn, Operation const& op, bool first,
  104. Linestring const& linestring, Polygon const& polygon)
  105. {
  106. if (first && (turn.method == method_collinear || turn.method == method_equal))
  107. {
  108. return last_covered_by(turn, op, linestring, polygon);
  109. }
  110. return false;
  111. }
  112. // Template specialization structure to call the right actions for the right type
  113. template<overlay_type OverlayType>
  114. struct action_selector
  115. {
  116. // If you get here the overlay type is not intersection or difference
  117. // BOOST_MPL_ASSERT(false);
  118. };
  119. // Specialization for intersection, containing the implementation
  120. template<>
  121. struct action_selector<overlay_intersection>
  122. {
  123. template
  124. <
  125. typename OutputIterator,
  126. typename LineStringOut,
  127. typename LineString,
  128. typename Point,
  129. typename Operation
  130. >
  131. static inline void enter(LineStringOut& current_piece,
  132. LineString const& ,
  133. segment_identifier& segment_id,
  134. int , Point const& point,
  135. Operation const& operation, OutputIterator& )
  136. {
  137. // On enter, append the intersection point and remember starting point
  138. detail::overlay::append_no_duplicates(current_piece, point);
  139. segment_id = operation.seg_id;
  140. }
  141. template
  142. <
  143. typename OutputIterator,
  144. typename LineStringOut,
  145. typename LineString,
  146. typename Point,
  147. typename Operation
  148. >
  149. static inline void leave(LineStringOut& current_piece,
  150. LineString const& linestring,
  151. segment_identifier& segment_id,
  152. int index, Point const& point,
  153. Operation const& , OutputIterator& out)
  154. {
  155. // On leave, copy all segments from starting point, append the intersection point
  156. // and add the output piece
  157. geometry::copy_segments<false>(linestring, segment_id, index, current_piece);
  158. detail::overlay::append_no_duplicates(current_piece, point);
  159. if (current_piece.size() > 1)
  160. {
  161. *out++ = current_piece;
  162. }
  163. current_piece.clear();
  164. }
  165. static inline bool is_entered(bool entered)
  166. {
  167. return entered;
  168. }
  169. template <typename Point, typename Geometry>
  170. static inline bool included(Point const& point, Geometry const& geometry)
  171. {
  172. return geometry::covered_by(point, geometry);
  173. }
  174. };
  175. // Specialization for difference, which reverses these actions
  176. template<>
  177. struct action_selector<overlay_difference>
  178. {
  179. typedef action_selector<overlay_intersection> normal_action;
  180. template
  181. <
  182. typename OutputIterator,
  183. typename LineStringOut,
  184. typename LineString,
  185. typename Point,
  186. typename Operation
  187. >
  188. static inline void enter(LineStringOut& current_piece,
  189. LineString const& linestring,
  190. segment_identifier& segment_id,
  191. int index, Point const& point,
  192. Operation const& operation, OutputIterator& out)
  193. {
  194. normal_action::leave(current_piece, linestring, segment_id, index,
  195. point, operation, out);
  196. }
  197. template
  198. <
  199. typename OutputIterator,
  200. typename LineStringOut,
  201. typename LineString,
  202. typename Point,
  203. typename Operation
  204. >
  205. static inline void leave(LineStringOut& current_piece,
  206. LineString const& linestring,
  207. segment_identifier& segment_id,
  208. int index, Point const& point,
  209. Operation const& operation, OutputIterator& out)
  210. {
  211. normal_action::enter(current_piece, linestring, segment_id, index,
  212. point, operation, out);
  213. }
  214. static inline bool is_entered(bool entered)
  215. {
  216. return ! normal_action::is_entered(entered);
  217. }
  218. template <typename Point, typename Geometry>
  219. static inline bool included(Point const& point, Geometry const& geometry)
  220. {
  221. return ! normal_action::included(point, geometry);
  222. }
  223. };
  224. }
  225. /*!
  226. \brief Follows a linestring from intersection point to intersection point, outputting which
  227. is inside, or outside, a ring or polygon
  228. \ingroup overlay
  229. */
  230. template
  231. <
  232. typename LineStringOut,
  233. typename LineString,
  234. typename Polygon,
  235. overlay_type OverlayType
  236. >
  237. class follow
  238. {
  239. template<typename Turn>
  240. struct sort_on_segment
  241. {
  242. // In case of turn point at the same location, we want to have continue/blocked LAST
  243. // because that should be followed (intersection) or skipped (difference).
  244. inline int operation_order(Turn const& turn) const
  245. {
  246. operation_type const& operation = turn.operations[0].operation;
  247. switch(operation)
  248. {
  249. case operation_opposite : return 0;
  250. case operation_none : return 0;
  251. case operation_union : return 1;
  252. case operation_intersection : return 2;
  253. case operation_blocked : return 3;
  254. case operation_continue : return 4;
  255. }
  256. return -1;
  257. };
  258. inline bool use_operation(Turn const& left, Turn const& right) const
  259. {
  260. // If they are the same, OK.
  261. return operation_order(left) < operation_order(right);
  262. }
  263. inline bool use_distance(Turn const& left, Turn const& right) const
  264. {
  265. return geometry::math::equals(left.operations[0].enriched.distance, right.operations[0].enriched.distance)
  266. ? use_operation(left, right)
  267. : left.operations[0].enriched.distance < right.operations[0].enriched.distance
  268. ;
  269. }
  270. inline bool operator()(Turn const& left, Turn const& right) const
  271. {
  272. segment_identifier const& sl = left.operations[0].seg_id;
  273. segment_identifier const& sr = right.operations[0].seg_id;
  274. return sl == sr
  275. ? use_distance(left, right)
  276. : sl < sr
  277. ;
  278. }
  279. };
  280. public :
  281. template <typename Point, typename Geometry>
  282. static inline bool included(Point const& point, Geometry const& geometry)
  283. {
  284. return following::action_selector<OverlayType>::included(point, geometry);
  285. }
  286. template<typename Turns, typename OutputIterator>
  287. static inline OutputIterator apply(LineString const& linestring, Polygon const& polygon,
  288. detail::overlay::operation_type , // TODO: this parameter might be redundant
  289. Turns& turns, OutputIterator out)
  290. {
  291. typedef typename boost::range_iterator<Turns>::type turn_iterator;
  292. typedef typename boost::range_value<Turns>::type turn_type;
  293. typedef typename boost::range_iterator
  294. <
  295. typename turn_type::container_type
  296. >::type turn_operation_iterator_type;
  297. typedef following::action_selector<OverlayType> action;
  298. // Sort intersection points on segments-along-linestring, and distance
  299. // (like in enrich is done for poly/poly)
  300. std::sort(boost::begin(turns), boost::end(turns), sort_on_segment<turn_type>());
  301. LineStringOut current_piece;
  302. geometry::segment_identifier current_segment_id(0, -1, -1, -1);
  303. // Iterate through all intersection points (they are ordered along the line)
  304. bool entered = false;
  305. bool first = true;
  306. for (turn_iterator it = boost::begin(turns); it != boost::end(turns); ++it)
  307. {
  308. turn_operation_iterator_type iit = boost::begin(it->operations);
  309. if (following::was_entered(*it, *iit, first, linestring, polygon))
  310. {
  311. debug_traverse(*it, *iit, "-> Was entered");
  312. entered = true;
  313. }
  314. if (following::is_staying_inside(*it, *iit, entered, first, linestring, polygon))
  315. {
  316. debug_traverse(*it, *iit, "-> Staying inside");
  317. entered = true;
  318. }
  319. else if (following::is_entering(*it, *iit))
  320. {
  321. debug_traverse(*it, *iit, "-> Entering");
  322. entered = true;
  323. action::enter(current_piece, linestring, current_segment_id, iit->seg_id.segment_index, it->point, *iit, out);
  324. }
  325. else if (following::is_leaving(*it, *iit, entered, first, linestring, polygon))
  326. {
  327. debug_traverse(*it, *iit, "-> Leaving");
  328. entered = false;
  329. action::leave(current_piece, linestring, current_segment_id, iit->seg_id.segment_index, it->point, *iit, out);
  330. }
  331. first = false;
  332. }
  333. if (action::is_entered(entered))
  334. {
  335. geometry::copy_segments<false>(linestring, current_segment_id,
  336. boost::size(linestring) - 1,
  337. current_piece);
  338. }
  339. // Output the last one, if applicable
  340. if (current_piece.size() > 1)
  341. {
  342. *out++ = current_piece;
  343. }
  344. return out;
  345. }
  346. };
  347. }} // namespace detail::overlay
  348. #endif // DOXYGEN_NO_DETAIL
  349. }} // namespace boost::geometry
  350. #endif // BOOST_GEOMETRY_ALGORITHMS_DETAIL_OVERLAY_FOLLOW_HPP