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