turn_in_original_visitor.hpp 8.1 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278
  1. // Boost.Geometry (aka GGL, Generic Geometry Library)
  2. // Copyright (c) 2014 Barend Gehrels, Amsterdam, the Netherlands.
  3. // This file was modified by Oracle on 2016, 2018.
  4. // Modifications copyright (c) 2016-2018 Oracle and/or its affiliates.
  5. // Contributed and/or modified by Adam Wulkiewicz, on behalf of Oracle
  6. // Use, modification and distribution is subject to the Boost Software License,
  7. // Version 1.0. (See accompanying file LICENSE_1_0.txt or copy at
  8. // http://www.boost.org/LICENSE_1_0.txt)
  9. #ifndef BOOST_GEOMETRY_ALGORITHMS_DETAIL_BUFFER_TURN_IN_ORIGINAL_VISITOR
  10. #define BOOST_GEOMETRY_ALGORITHMS_DETAIL_BUFFER_TURN_IN_ORIGINAL_VISITOR
  11. #include <boost/core/ignore_unused.hpp>
  12. #include <boost/geometry/algorithms/detail/buffer/buffer_policies.hpp>
  13. #include <boost/geometry/algorithms/expand.hpp>
  14. #include <boost/geometry/strategies/agnostic/point_in_poly_winding.hpp>
  15. #include <boost/geometry/strategies/buffer.hpp>
  16. namespace boost { namespace geometry
  17. {
  18. #ifndef DOXYGEN_NO_DETAIL
  19. namespace detail { namespace buffer
  20. {
  21. struct original_get_box
  22. {
  23. template <typename Box, typename Original>
  24. static inline void apply(Box& total, Original const& original)
  25. {
  26. geometry::expand(total, original.m_box);
  27. }
  28. };
  29. template <typename DisjointBoxBoxStrategy>
  30. struct original_ovelaps_box
  31. {
  32. template <typename Box, typename Original>
  33. static inline bool apply(Box const& box, Original const& original)
  34. {
  35. return ! detail::disjoint::disjoint_box_box(box, original.m_box,
  36. DisjointBoxBoxStrategy());
  37. }
  38. };
  39. struct include_turn_policy
  40. {
  41. template <typename Turn>
  42. static inline bool apply(Turn const& turn)
  43. {
  44. return turn.location == location_ok;
  45. }
  46. };
  47. template <typename DisjointPointBoxStrategy>
  48. struct turn_in_original_ovelaps_box
  49. {
  50. template <typename Box, typename Turn>
  51. static inline bool apply(Box const& box, Turn const& turn)
  52. {
  53. if (turn.location != location_ok || turn.within_original)
  54. {
  55. // Skip all points already processed
  56. return false;
  57. }
  58. return ! geometry::detail::disjoint::disjoint_point_box(
  59. turn.robust_point, box, DisjointPointBoxStrategy());
  60. }
  61. };
  62. //! Check if specified is in range of specified iterators
  63. //! Return value of strategy (true if we can bail out)
  64. template
  65. <
  66. typename Strategy,
  67. typename State,
  68. typename Point,
  69. typename Iterator
  70. >
  71. inline bool point_in_range(Strategy& strategy, State& state,
  72. Point const& point, Iterator begin, Iterator end)
  73. {
  74. boost::ignore_unused(strategy);
  75. Iterator it = begin;
  76. for (Iterator previous = it++; it != end; ++previous, ++it)
  77. {
  78. if (! strategy.apply(point, *previous, *it, state))
  79. {
  80. // We're probably on the boundary
  81. return false;
  82. }
  83. }
  84. return true;
  85. }
  86. template
  87. <
  88. typename Strategy,
  89. typename State,
  90. typename Point,
  91. typename CoordinateType,
  92. typename Iterator
  93. >
  94. inline bool point_in_section(Strategy& strategy, State& state,
  95. Point const& point, CoordinateType const& point_x,
  96. Iterator begin, Iterator end,
  97. int direction)
  98. {
  99. if (direction == 0)
  100. {
  101. // Not a monotonic section, or no change in X-direction
  102. return point_in_range(strategy, state, point, begin, end);
  103. }
  104. // We're in a monotonic section in x-direction
  105. Iterator it = begin;
  106. for (Iterator previous = it++; it != end; ++previous, ++it)
  107. {
  108. // Depending on sections.direction we can quit for this section
  109. CoordinateType const previous_x = geometry::get<0>(*previous);
  110. if (direction == 1 && point_x < previous_x)
  111. {
  112. // Section goes upwards, x increases, point is is below section
  113. return true;
  114. }
  115. else if (direction == -1 && point_x > previous_x)
  116. {
  117. // Section goes downwards, x decreases, point is above section
  118. return true;
  119. }
  120. if (! strategy.apply(point, *previous, *it, state))
  121. {
  122. // We're probably on the boundary
  123. return false;
  124. }
  125. }
  126. return true;
  127. }
  128. template <typename Point, typename Original, typename PointInGeometryStrategy>
  129. inline int point_in_original(Point const& point, Original const& original,
  130. PointInGeometryStrategy const& strategy)
  131. {
  132. typename PointInGeometryStrategy::state_type state;
  133. if (boost::size(original.m_sections) == 0
  134. || boost::size(original.m_ring) - boost::size(original.m_sections) < 16)
  135. {
  136. // There are no sections, or it does not profit to walk over sections
  137. // instead of over points. Boundary of 16 is arbitrary but can influence
  138. // performance
  139. point_in_range(strategy, state, point,
  140. original.m_ring.begin(), original.m_ring.end());
  141. return strategy.result(state);
  142. }
  143. typedef typename Original::sections_type sections_type;
  144. typedef typename boost::range_iterator<sections_type const>::type iterator_type;
  145. typedef typename boost::range_value<sections_type const>::type section_type;
  146. typedef typename geometry::coordinate_type<Point>::type coordinate_type;
  147. coordinate_type const point_x = geometry::get<0>(point);
  148. // Walk through all monotonic sections of this original
  149. for (iterator_type it = boost::begin(original.m_sections);
  150. it != boost::end(original.m_sections);
  151. ++it)
  152. {
  153. section_type const& section = *it;
  154. if (! section.duplicate
  155. && section.begin_index < section.end_index
  156. && point_x >= geometry::get<min_corner, 0>(section.bounding_box)
  157. && point_x <= geometry::get<max_corner, 0>(section.bounding_box))
  158. {
  159. // x-coordinate of point overlaps with section
  160. if (! point_in_section(strategy, state, point, point_x,
  161. boost::begin(original.m_ring) + section.begin_index,
  162. boost::begin(original.m_ring) + section.end_index + 1,
  163. section.directions[0]))
  164. {
  165. // We're probably on the boundary
  166. break;
  167. }
  168. }
  169. }
  170. return strategy.result(state);
  171. }
  172. template <typename Turns, typename PointInGeometryStrategy>
  173. class turn_in_original_visitor
  174. {
  175. public:
  176. turn_in_original_visitor(Turns& turns, PointInGeometryStrategy const& strategy)
  177. : m_mutable_turns(turns)
  178. , m_point_in_geometry_strategy(strategy)
  179. {}
  180. template <typename Turn, typename Original>
  181. inline bool apply(Turn const& turn, Original const& original, bool first = true)
  182. {
  183. boost::ignore_unused(first);
  184. if (turn.location != location_ok || turn.within_original)
  185. {
  186. // Skip all points already processed
  187. return true;
  188. }
  189. if (geometry::disjoint(turn.robust_point, original.m_box))
  190. {
  191. // Skip all disjoint
  192. return true;
  193. }
  194. int const code = point_in_original(turn.robust_point, original, m_point_in_geometry_strategy);
  195. if (code == -1)
  196. {
  197. return true;
  198. }
  199. Turn& mutable_turn = m_mutable_turns[turn.turn_index];
  200. if (code == 0)
  201. {
  202. // On border of original: always discard
  203. mutable_turn.location = location_discard;
  204. }
  205. // Point is inside an original ring
  206. if (original.m_is_interior)
  207. {
  208. mutable_turn.count_in_original--;
  209. }
  210. else if (original.m_has_interiors)
  211. {
  212. mutable_turn.count_in_original++;
  213. }
  214. else
  215. {
  216. // It is an exterior ring and there are no interior rings.
  217. // Then we are completely ready with this turn
  218. mutable_turn.within_original = true;
  219. mutable_turn.count_in_original = 1;
  220. }
  221. return true;
  222. }
  223. private :
  224. Turns& m_mutable_turns;
  225. PointInGeometryStrategy const& m_point_in_geometry_strategy;
  226. };
  227. }} // namespace detail::buffer
  228. #endif // DOXYGEN_NO_DETAIL
  229. }} // namespace boost::geometry
  230. #endif // BOOST_GEOMETRY_ALGORITHMS_DETAIL_BUFFER_TURN_IN_ORIGINAL_VISITOR