get_piece_turns.hpp 12 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336
  1. // Boost.Geometry (aka GGL, Generic Geometry Library)
  2. // Copyright (c) 2012-2014 Barend Gehrels, Amsterdam, the Netherlands.
  3. // Copyright (c) 2017 Adam Wulkiewicz, Lodz, Poland.
  4. // This file was modified by Oracle on 2017, 2018.
  5. // Modifications copyright (c) 2017-2018 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_BUFFER_GET_PIECE_TURNS_HPP
  11. #define BOOST_GEOMETRY_ALGORITHMS_DETAIL_BUFFER_GET_PIECE_TURNS_HPP
  12. #include <boost/core/ignore_unused.hpp>
  13. #include <boost/range.hpp>
  14. #include <boost/geometry/core/assert.hpp>
  15. #include <boost/geometry/algorithms/equals.hpp>
  16. #include <boost/geometry/algorithms/detail/disjoint/box_box.hpp>
  17. #include <boost/geometry/algorithms/detail/overlay/segment_identifier.hpp>
  18. #include <boost/geometry/algorithms/detail/overlay/get_turn_info.hpp>
  19. #include <boost/geometry/algorithms/detail/sections/section_functions.hpp>
  20. #include <boost/geometry/algorithms/detail/buffer/buffer_policies.hpp>
  21. namespace boost { namespace geometry
  22. {
  23. #ifndef DOXYGEN_NO_DETAIL
  24. namespace detail { namespace buffer
  25. {
  26. // Implements a unique_sub_range for a buffered piece,
  27. // the range can return subsequent points
  28. // known as "i", "j" and "k" (and further), indexed as 0,1,2,3
  29. template <typename Ring>
  30. struct unique_sub_range_from_piece
  31. {
  32. typedef typename boost::range_iterator<Ring const>::type iterator_type;
  33. typedef typename geometry::point_type<Ring const>::type point_type;
  34. unique_sub_range_from_piece(Ring const& ring,
  35. iterator_type iterator_at_i, iterator_type iterator_at_j)
  36. : m_ring(ring)
  37. , m_iterator_at_i(iterator_at_i)
  38. , m_iterator_at_j(iterator_at_j)
  39. , m_point_retrieved(false)
  40. {}
  41. static inline bool is_first_segment() { return false; }
  42. static inline bool is_last_segment() { return false; }
  43. static inline std::size_t size() { return 3u; }
  44. inline point_type const& at(std::size_t index) const
  45. {
  46. BOOST_GEOMETRY_ASSERT(index < size());
  47. switch (index)
  48. {
  49. case 0 : return *m_iterator_at_i;
  50. case 1 : return *m_iterator_at_j;
  51. case 2 : return get_point_k();
  52. default : return *m_iterator_at_i;
  53. }
  54. }
  55. private :
  56. inline point_type const& get_point_k() const
  57. {
  58. if (! m_point_retrieved)
  59. {
  60. m_iterator_at_k = advance_one(m_iterator_at_j);
  61. m_point_retrieved = true;
  62. }
  63. return *m_iterator_at_k;
  64. }
  65. inline void circular_advance_one(iterator_type& next) const
  66. {
  67. ++next;
  68. if (next == boost::end(m_ring))
  69. {
  70. next = boost::begin(m_ring) + 1;
  71. }
  72. }
  73. inline iterator_type advance_one(iterator_type it) const
  74. {
  75. iterator_type result = it;
  76. circular_advance_one(result);
  77. // TODO: we could also use piece-boundaries
  78. // to check if the point equals the last one
  79. while (geometry::equals(*it, *result))
  80. {
  81. circular_advance_one(result);
  82. }
  83. return result;
  84. }
  85. Ring const& m_ring;
  86. iterator_type m_iterator_at_i;
  87. iterator_type m_iterator_at_j;
  88. mutable iterator_type m_iterator_at_k;
  89. mutable bool m_point_retrieved;
  90. };
  91. template
  92. <
  93. typename Pieces,
  94. typename Rings,
  95. typename Turns,
  96. typename IntersectionStrategy,
  97. typename RobustPolicy
  98. >
  99. class piece_turn_visitor
  100. {
  101. Pieces const& m_pieces;
  102. Rings const& m_rings;
  103. Turns& m_turns;
  104. IntersectionStrategy const& m_intersection_strategy;
  105. RobustPolicy const& m_robust_policy;
  106. template <typename Piece>
  107. inline bool is_adjacent(Piece const& piece1, Piece const& piece2) const
  108. {
  109. if (piece1.first_seg_id.multi_index != piece2.first_seg_id.multi_index)
  110. {
  111. return false;
  112. }
  113. return piece1.index == piece2.left_index
  114. || piece1.index == piece2.right_index;
  115. }
  116. template <typename Piece>
  117. inline bool is_on_same_convex_ring(Piece const& piece1, Piece const& piece2) const
  118. {
  119. if (piece1.first_seg_id.multi_index != piece2.first_seg_id.multi_index)
  120. {
  121. return false;
  122. }
  123. return ! m_rings[piece1.first_seg_id.multi_index].has_concave;
  124. }
  125. template <std::size_t Dimension, typename Iterator, typename Box>
  126. inline void move_begin_iterator(Iterator& it_begin, Iterator it_beyond,
  127. signed_size_type& index, int dir,
  128. Box const& this_bounding_box,
  129. Box const& other_bounding_box)
  130. {
  131. for(; it_begin != it_beyond
  132. && it_begin + 1 != it_beyond
  133. && detail::section::preceding<Dimension>(dir, *(it_begin + 1),
  134. this_bounding_box,
  135. other_bounding_box,
  136. m_robust_policy);
  137. ++it_begin, index++)
  138. {}
  139. }
  140. template <std::size_t Dimension, typename Iterator, typename Box>
  141. inline void move_end_iterator(Iterator it_begin, Iterator& it_beyond,
  142. int dir, Box const& this_bounding_box,
  143. Box const& other_bounding_box)
  144. {
  145. while (it_beyond != it_begin
  146. && it_beyond - 1 != it_begin
  147. && it_beyond - 2 != it_begin)
  148. {
  149. if (detail::section::exceeding<Dimension>(dir, *(it_beyond - 2),
  150. this_bounding_box, other_bounding_box, m_robust_policy))
  151. {
  152. --it_beyond;
  153. }
  154. else
  155. {
  156. return;
  157. }
  158. }
  159. }
  160. template <typename Piece, typename Section>
  161. inline void calculate_turns(Piece const& piece1, Piece const& piece2,
  162. Section const& section1, Section const& section2)
  163. {
  164. typedef typename boost::range_value<Rings const>::type ring_type;
  165. typedef typename boost::range_value<Turns const>::type turn_type;
  166. typedef typename boost::range_iterator<ring_type const>::type iterator;
  167. signed_size_type const piece1_first_index = piece1.first_seg_id.segment_index;
  168. signed_size_type const piece2_first_index = piece2.first_seg_id.segment_index;
  169. if (piece1_first_index < 0 || piece2_first_index < 0)
  170. {
  171. return;
  172. }
  173. // Get indices of part of offsetted_rings for this monotonic section:
  174. signed_size_type const sec1_first_index = piece1_first_index + section1.begin_index;
  175. signed_size_type const sec2_first_index = piece2_first_index + section2.begin_index;
  176. // index of last point in section, beyond-end is one further
  177. signed_size_type const sec1_last_index = piece1_first_index + section1.end_index;
  178. signed_size_type const sec2_last_index = piece2_first_index + section2.end_index;
  179. // get geometry and iterators over these sections
  180. ring_type const& ring1 = m_rings[piece1.first_seg_id.multi_index];
  181. iterator it1_first = boost::begin(ring1) + sec1_first_index;
  182. iterator it1_beyond = boost::begin(ring1) + sec1_last_index + 1;
  183. ring_type const& ring2 = m_rings[piece2.first_seg_id.multi_index];
  184. iterator it2_first = boost::begin(ring2) + sec2_first_index;
  185. iterator it2_beyond = boost::begin(ring2) + sec2_last_index + 1;
  186. // Set begin/end of monotonic ranges, in both x/y directions
  187. signed_size_type index1 = sec1_first_index;
  188. move_begin_iterator<0>(it1_first, it1_beyond, index1,
  189. section1.directions[0], section1.bounding_box, section2.bounding_box);
  190. move_end_iterator<0>(it1_first, it1_beyond,
  191. section1.directions[0], section1.bounding_box, section2.bounding_box);
  192. move_begin_iterator<1>(it1_first, it1_beyond, index1,
  193. section1.directions[1], section1.bounding_box, section2.bounding_box);
  194. move_end_iterator<1>(it1_first, it1_beyond,
  195. section1.directions[1], section1.bounding_box, section2.bounding_box);
  196. signed_size_type index2 = sec2_first_index;
  197. move_begin_iterator<0>(it2_first, it2_beyond, index2,
  198. section2.directions[0], section2.bounding_box, section1.bounding_box);
  199. move_end_iterator<0>(it2_first, it2_beyond,
  200. section2.directions[0], section2.bounding_box, section1.bounding_box);
  201. move_begin_iterator<1>(it2_first, it2_beyond, index2,
  202. section2.directions[1], section2.bounding_box, section1.bounding_box);
  203. move_end_iterator<1>(it2_first, it2_beyond,
  204. section2.directions[1], section2.bounding_box, section1.bounding_box);
  205. turn_type the_model;
  206. the_model.operations[0].piece_index = piece1.index;
  207. the_model.operations[0].seg_id = piece1.first_seg_id;
  208. the_model.operations[0].seg_id.segment_index = index1; // override
  209. iterator it1 = it1_first;
  210. for (iterator prev1 = it1++;
  211. it1 != it1_beyond;
  212. prev1 = it1++, the_model.operations[0].seg_id.segment_index++)
  213. {
  214. the_model.operations[1].piece_index = piece2.index;
  215. the_model.operations[1].seg_id = piece2.first_seg_id;
  216. the_model.operations[1].seg_id.segment_index = index2; // override
  217. geometry::recalculate(the_model.rob_pi, *prev1, m_robust_policy);
  218. geometry::recalculate(the_model.rob_pj, *it1, m_robust_policy);
  219. unique_sub_range_from_piece<ring_type> unique_sub_range1(ring1, prev1, it1);
  220. iterator it2 = it2_first;
  221. for (iterator prev2 = it2++;
  222. it2 != it2_beyond;
  223. prev2 = it2++, the_model.operations[1].seg_id.segment_index++)
  224. {
  225. unique_sub_range_from_piece<ring_type> unique_sub_range2(ring2, prev2, it2);
  226. geometry::recalculate(the_model.rob_qi, *prev2, m_robust_policy);
  227. geometry::recalculate(the_model.rob_qj, *it2, m_robust_policy);
  228. // TODO: internally get_turn_info calculates robust points.
  229. // But they are already calculated.
  230. // We should be able to use them.
  231. // this means passing them to this visitor,
  232. // and iterating in sync with them...
  233. typedef detail::overlay::get_turn_info
  234. <
  235. detail::overlay::assign_null_policy
  236. > turn_policy;
  237. turn_policy::apply(unique_sub_range1, unique_sub_range2,
  238. the_model,
  239. m_intersection_strategy,
  240. m_robust_policy,
  241. std::back_inserter(m_turns));
  242. }
  243. }
  244. }
  245. public:
  246. piece_turn_visitor(Pieces const& pieces,
  247. Rings const& ring_collection,
  248. Turns& turns,
  249. IntersectionStrategy const& intersection_strategy,
  250. RobustPolicy const& robust_policy)
  251. : m_pieces(pieces)
  252. , m_rings(ring_collection)
  253. , m_turns(turns)
  254. , m_intersection_strategy(intersection_strategy)
  255. , m_robust_policy(robust_policy)
  256. {}
  257. template <typename Section>
  258. inline bool apply(Section const& section1, Section const& section2,
  259. bool first = true)
  260. {
  261. boost::ignore_unused(first);
  262. typedef typename boost::range_value<Pieces const>::type piece_type;
  263. piece_type const& piece1 = m_pieces[section1.ring_id.source_index];
  264. piece_type const& piece2 = m_pieces[section2.ring_id.source_index];
  265. if ( piece1.index == piece2.index
  266. || is_adjacent(piece1, piece2)
  267. || is_on_same_convex_ring(piece1, piece2)
  268. || detail::disjoint::disjoint_box_box(section1.bounding_box,
  269. section2.bounding_box,
  270. m_intersection_strategy.get_disjoint_box_box_strategy()) )
  271. {
  272. return true;
  273. }
  274. calculate_turns(piece1, piece2, section1, section2);
  275. return true;
  276. }
  277. };
  278. }} // namespace detail::buffer
  279. #endif // DOXYGEN_NO_DETAIL
  280. }} // namespace boost::geometry
  281. #endif // BOOST_GEOMETRY_ALGORITHMS_DETAIL_BUFFER_GET_PIECE_TURNS_HPP