]>
Commit | Line | Data |
---|---|---|
7c673cae FG |
1 | // Boost.Geometry (aka GGL, Generic Geometry Library) |
2 | ||
3 | // Copyright (c) 2007-2012 Barend Gehrels, Amsterdam, the Netherlands. | |
4 | ||
5 | // This file was modified by Oracle on 2013, 2014. | |
6 | // Modifications copyright (c) 2013-2014 Oracle and/or its affiliates. | |
7 | ||
8 | // Use, modification and distribution is subject to the Boost Software License, | |
9 | // Version 1.0. (See accompanying file LICENSE_1_0.txt or copy at | |
10 | // http://www.boost.org/LICENSE_1_0.txt) | |
11 | ||
12 | // Contributed and/or modified by Adam Wulkiewicz, on behalf of Oracle | |
13 | ||
14 | #ifndef BOOST_GEOMETRY_ALGORITHMS_DETAIL_OVERLAY_GET_TURN_INFO_FOR_ENDPOINT_HPP | |
15 | #define BOOST_GEOMETRY_ALGORITHMS_DETAIL_OVERLAY_GET_TURN_INFO_FOR_ENDPOINT_HPP | |
16 | ||
17 | #include <boost/geometry/core/assert.hpp> | |
18 | #include <boost/geometry/algorithms/detail/overlay/get_turn_info.hpp> | |
19 | #include <boost/geometry/policies/robustness/no_rescale_policy.hpp> | |
20 | ||
21 | namespace boost { namespace geometry { | |
22 | ||
23 | #ifndef DOXYGEN_NO_DETAIL | |
24 | namespace detail { namespace overlay { | |
25 | ||
26 | // SEGMENT_INTERSECTION RESULT | |
27 | ||
28 | // C H0 H1 A0 A1 O IP1 IP2 | |
29 | ||
30 | // D0 and D1 == 0 | |
31 | ||
32 | // |--------> 2 0 0 0 0 F i/i x/x | |
33 | // |--------> | |
34 | // | |
35 | // |--------> 2 0 0 0 0 T i/x x/i | |
36 | // <--------| | |
37 | // | |
38 | // |-----> 1 0 0 0 0 T x/x | |
39 | // <-----| | |
40 | // | |
41 | ||
42 | // |---------> 2 0 0 0 1 T i/x x/i | |
43 | // <----| | |
44 | // | |
45 | // |---------> 2 0 0 0 0 F i/i x/x | |
46 | // |----> | |
47 | // | |
48 | // |---------> 2 0 0 -1 1 F i/i u/x | |
49 | // |----> | |
50 | // | |
51 | // |---------> 2 0 0 -1 0 T i/x u/i | |
52 | // <----| | |
53 | ||
54 | // |-------> 2 0 0 1 -1 F and i/i x/u | |
55 | // |-------> 2 0 0 -1 1 F symetric i/i u/x | |
56 | // |-------> | |
57 | // | |
58 | // |-------> 2 0 0 -1 -1 T i/u u/i | |
59 | // <-------| | |
60 | // | |
61 | // |-------> 2 0 0 1 1 T i/x x/i | |
62 | // <-------| | |
63 | // | |
64 | // |--------> 2 0 0 -1 1 F i/i u/x | |
65 | // |----> | |
66 | // | |
67 | // |--------> 2 0 0 -1 1 T i/x u/i | |
68 | // <----| | |
69 | ||
70 | // |-----> 1 -1 -1 -1 -1 T u/u | |
71 | // <-----| | |
72 | // | |
73 | // |-----> 1 -1 0 -1 0 F and u/x | |
74 | // |-----> 1 0 -1 0 -1 F symetric x/u | |
75 | // |-----> | |
76 | ||
77 | // D0 or D1 != 0 | |
78 | ||
79 | // ^ | |
80 | // | | |
81 | // + 1 -1 1 -1 1 F and u/x (P is vertical) | |
82 | // |--------> 1 1 -1 1 -1 F symetric x/u (P is horizontal) | |
83 | // ^ | |
84 | // | | |
85 | // + | |
86 | // | |
87 | // + | |
88 | // | | |
89 | // v | |
90 | // |--------> 1 1 1 1 1 F x/x (P is vertical) | |
91 | // | |
92 | // ^ | |
93 | // | | |
94 | // + | |
95 | // |--------> 1 -1 -1 -1 -1 F u/u (P is vertical) | |
96 | // | |
97 | // ^ | |
98 | // | | |
99 | // + | |
100 | // |--------> 1 0 -1 0 -1 F u/u (P is vertical) | |
101 | // | |
102 | // + | |
103 | // | | |
104 | // v | |
105 | // |--------> 1 0 1 0 1 F u/x (P is vertical) | |
106 | // | |
107 | ||
108 | class linear_intersections | |
109 | { | |
110 | public: | |
111 | template <typename Point1, typename Point2, typename IntersectionResult> | |
112 | linear_intersections(Point1 const& pi, | |
113 | Point2 const& qi, | |
114 | IntersectionResult const& result, | |
115 | bool is_p_last, bool is_q_last) | |
116 | { | |
117 | int arrival_a = result.template get<1>().arrival[0]; | |
118 | int arrival_b = result.template get<1>().arrival[1]; | |
119 | bool same_dirs = result.template get<1>().dir_a == 0 | |
120 | && result.template get<1>().dir_b == 0; | |
121 | ||
122 | if ( same_dirs ) | |
123 | { | |
124 | if ( result.template get<0>().count == 2 ) | |
125 | { | |
126 | if ( ! result.template get<1>().opposite ) | |
127 | { | |
128 | ips[0].p_operation = operation_intersection; | |
129 | ips[0].q_operation = operation_intersection; | |
130 | ips[1].p_operation = union_or_blocked_same_dirs(arrival_a, is_p_last); | |
131 | ips[1].q_operation = union_or_blocked_same_dirs(arrival_b, is_q_last); | |
132 | ||
133 | ips[0].is_pi | |
134 | = equals::equals_point_point( | |
135 | pi, result.template get<0>().intersections[0]); | |
136 | ips[0].is_qi | |
137 | = equals::equals_point_point( | |
138 | qi, result.template get<0>().intersections[0]); | |
139 | ips[1].is_pj = arrival_a != -1; | |
140 | ips[1].is_qj = arrival_b != -1; | |
141 | } | |
142 | else | |
143 | { | |
144 | ips[0].p_operation = operation_intersection; | |
145 | ips[0].q_operation = union_or_blocked_same_dirs(arrival_b, is_q_last); | |
146 | ips[1].p_operation = union_or_blocked_same_dirs(arrival_a, is_p_last); | |
147 | ips[1].q_operation = operation_intersection; | |
148 | ||
149 | ips[0].is_pi = arrival_b != 1; | |
150 | ips[0].is_qj = arrival_b != -1; | |
151 | ips[1].is_pj = arrival_a != -1; | |
152 | ips[1].is_qi = arrival_a != 1; | |
153 | } | |
154 | } | |
155 | else | |
156 | { | |
157 | BOOST_GEOMETRY_ASSERT(result.template get<0>().count == 1); | |
158 | ips[0].p_operation = union_or_blocked_same_dirs(arrival_a, is_p_last); | |
159 | ips[0].q_operation = union_or_blocked_same_dirs(arrival_b, is_q_last); | |
160 | ||
161 | ips[0].is_pi = arrival_a == -1; | |
162 | ips[0].is_qi = arrival_b == -1; | |
163 | ips[0].is_pj = arrival_a == 0; | |
164 | ips[0].is_qj = arrival_b == 0; | |
165 | } | |
166 | } | |
167 | else | |
168 | { | |
169 | ips[0].p_operation = union_or_blocked_different_dirs(arrival_a, is_p_last); | |
170 | ips[0].q_operation = union_or_blocked_different_dirs(arrival_b, is_q_last); | |
171 | ||
172 | ips[0].is_pi = arrival_a == -1; | |
173 | ips[0].is_qi = arrival_b == -1; | |
174 | ips[0].is_pj = arrival_a == 1; | |
175 | ips[0].is_qj = arrival_b == 1; | |
176 | } | |
177 | } | |
178 | ||
179 | struct ip_info | |
180 | { | |
181 | inline ip_info() | |
182 | : p_operation(operation_none), q_operation(operation_none) | |
183 | , is_pi(false), is_pj(false), is_qi(false), is_qj(false) | |
184 | {} | |
185 | ||
186 | operation_type p_operation, q_operation; | |
187 | bool is_pi, is_pj, is_qi, is_qj; | |
188 | }; | |
189 | ||
190 | template <std::size_t I> | |
191 | ip_info const& get() const | |
192 | { | |
193 | BOOST_STATIC_ASSERT(I < 2); | |
194 | return ips[I]; | |
195 | } | |
196 | ||
197 | private: | |
198 | ||
199 | // only if collinear (same_dirs) | |
200 | static inline operation_type union_or_blocked_same_dirs(int arrival, bool is_last) | |
201 | { | |
202 | if ( arrival == 1 ) | |
203 | return operation_blocked; | |
204 | else if ( arrival == -1 ) | |
205 | return operation_union; | |
206 | else | |
207 | return is_last ? operation_blocked : operation_union; | |
208 | //return operation_blocked; | |
209 | } | |
210 | ||
211 | // only if not collinear (!same_dirs) | |
212 | static inline operation_type union_or_blocked_different_dirs(int arrival, bool is_last) | |
213 | { | |
214 | if ( arrival == 1 ) | |
215 | //return operation_blocked; | |
216 | return is_last ? operation_blocked : operation_union; | |
217 | else | |
218 | return operation_union; | |
219 | } | |
220 | ||
221 | ip_info ips[2]; | |
222 | }; | |
223 | ||
224 | template <typename AssignPolicy, bool EnableFirst, bool EnableLast> | |
225 | struct get_turn_info_for_endpoint | |
226 | { | |
227 | BOOST_STATIC_ASSERT(EnableFirst || EnableLast); | |
228 | ||
229 | template<typename Point1, | |
230 | typename Point2, | |
231 | typename TurnInfo, | |
232 | typename IntersectionInfo, | |
233 | typename OutputIterator | |
234 | > | |
235 | static inline bool apply(Point1 const& pi, Point1 const& pj, Point1 const& pk, | |
236 | Point2 const& qi, Point2 const& qj, Point2 const& qk, | |
237 | bool is_p_first, bool is_p_last, | |
238 | bool is_q_first, bool is_q_last, | |
239 | TurnInfo const& tp_model, | |
240 | IntersectionInfo const& inters, | |
241 | method_type /*method*/, | |
242 | OutputIterator out) | |
243 | { | |
244 | std::size_t ip_count = inters.i_info().count; | |
245 | // no intersection points | |
246 | if ( ip_count == 0 ) | |
247 | return false; | |
248 | ||
249 | if ( !is_p_first && !is_p_last && !is_q_first && !is_q_last ) | |
250 | return false; | |
251 | ||
252 | linear_intersections intersections(pi, qi, inters.result(), is_p_last, is_q_last); | |
253 | ||
254 | bool append0_last | |
255 | = analyse_segment_and_assign_ip(pi, pj, pk, qi, qj, qk, | |
256 | is_p_first, is_p_last, is_q_first, is_q_last, | |
257 | intersections.template get<0>(), | |
258 | tp_model, inters, 0, out); | |
259 | ||
260 | // NOTE: opposite && ip_count == 1 may be true! | |
261 | bool opposite = inters.d_info().opposite; | |
262 | ||
263 | // don't ignore only for collinear opposite | |
264 | bool result_ignore_ip0 = append0_last && ( ip_count == 1 || !opposite ); | |
265 | ||
266 | if ( intersections.template get<1>().p_operation == operation_none ) | |
267 | return result_ignore_ip0; | |
268 | ||
269 | bool append1_last | |
270 | = analyse_segment_and_assign_ip(pi, pj, pk, qi, qj, qk, | |
271 | is_p_first, is_p_last, is_q_first, is_q_last, | |
272 | intersections.template get<1>(), | |
273 | tp_model, inters, 1, out); | |
274 | ||
275 | // don't ignore only for collinear opposite | |
276 | bool result_ignore_ip1 = append1_last && !opposite /*&& ip_count == 2*/; | |
277 | ||
278 | return result_ignore_ip0 || result_ignore_ip1; | |
279 | } | |
280 | ||
281 | template <typename Point1, | |
282 | typename Point2, | |
283 | typename TurnInfo, | |
284 | typename IntersectionInfo, | |
285 | typename OutputIterator> | |
286 | static inline | |
287 | bool analyse_segment_and_assign_ip(Point1 const& pi, Point1 const& pj, Point1 const& pk, | |
288 | Point2 const& qi, Point2 const& qj, Point2 const& qk, | |
289 | bool is_p_first, bool is_p_last, | |
290 | bool is_q_first, bool is_q_last, | |
291 | linear_intersections::ip_info const& ip_info, | |
292 | TurnInfo const& tp_model, | |
293 | IntersectionInfo const& inters, | |
294 | unsigned int ip_index, | |
295 | OutputIterator out) | |
296 | { | |
297 | #ifdef BOOST_GEOMETRY_DEBUG_GET_TURNS_LINEAR_LINEAR | |
298 | // may this give false positives for INTs? | |
299 | typename IntersectionResult::point_type const& | |
300 | inters_pt = result.template get<0>().intersections[ip_index]; | |
301 | BOOST_GEOMETRY_ASSERT(ip_info.is_pi == equals::equals_point_point(pi, inters_pt)); | |
302 | BOOST_GEOMETRY_ASSERT(ip_info.is_qi == equals::equals_point_point(qi, inters_pt)); | |
303 | BOOST_GEOMETRY_ASSERT(ip_info.is_pj == equals::equals_point_point(pj, inters_pt)); | |
304 | BOOST_GEOMETRY_ASSERT(ip_info.is_qj == equals::equals_point_point(qj, inters_pt)); | |
305 | #endif | |
306 | ||
307 | // TODO - calculate first/last only if needed | |
308 | bool is_p_first_ip = is_p_first && ip_info.is_pi; | |
309 | bool is_p_last_ip = is_p_last && ip_info.is_pj; | |
310 | bool is_q_first_ip = is_q_first && ip_info.is_qi; | |
311 | bool is_q_last_ip = is_q_last && ip_info.is_qj; | |
312 | bool append_first = EnableFirst && (is_p_first_ip || is_q_first_ip); | |
313 | bool append_last = EnableLast && (is_p_last_ip || is_q_last_ip); | |
314 | ||
315 | operation_type p_operation = ip_info.p_operation; | |
316 | operation_type q_operation = ip_info.q_operation; | |
317 | ||
318 | if ( append_first || append_last ) | |
319 | { | |
320 | bool handled = handle_internal<0>(pi, pj, pk, qi, qj, qk, | |
321 | inters.rpi(), inters.rpj(), inters.rpk(), | |
322 | inters.rqi(), inters.rqj(), inters.rqk(), | |
323 | is_p_first_ip, is_p_last_ip, | |
324 | is_q_first_ip, is_q_last_ip, | |
325 | ip_info.is_qi, ip_info.is_qj, | |
326 | tp_model, inters, ip_index, | |
327 | p_operation, q_operation); | |
328 | if ( !handled ) | |
329 | { | |
330 | handle_internal<1>(qi, qj, qk, pi, pj, pk, | |
331 | inters.rqi(), inters.rqj(), inters.rqk(), | |
332 | inters.rpi(), inters.rpj(), inters.rpk(), | |
333 | is_q_first_ip, is_q_last_ip, | |
334 | is_p_first_ip, is_p_last_ip, | |
335 | ip_info.is_pi, ip_info.is_pj, | |
336 | tp_model, inters, ip_index, | |
337 | q_operation, p_operation); | |
338 | } | |
339 | ||
340 | if ( p_operation != operation_none ) | |
341 | { | |
342 | method_type method = endpoint_ip_method(ip_info.is_pi, ip_info.is_pj, | |
343 | ip_info.is_qi, ip_info.is_qj); | |
344 | turn_position p_pos = ip_position(is_p_first_ip, is_p_last_ip); | |
345 | turn_position q_pos = ip_position(is_q_first_ip, is_q_last_ip); | |
346 | ||
347 | // handle spikes | |
348 | ||
349 | // P is spike and should be handled | |
350 | if ( !is_p_last | |
351 | && ip_info.is_pj // this check is redundant (also in is_spike_p) but faster | |
352 | && inters.i_info().count == 2 | |
353 | && inters.is_spike_p() ) | |
354 | { | |
355 | assign(pi, qi, inters.result(), ip_index, method, operation_blocked, q_operation, | |
356 | p_pos, q_pos, is_p_first_ip, is_q_first_ip, true, false, tp_model, out); | |
357 | assign(pi, qi, inters.result(), ip_index, method, operation_intersection, q_operation, | |
358 | p_pos, q_pos, is_p_first_ip, is_q_first_ip, true, false, tp_model, out); | |
359 | } | |
360 | // Q is spike and should be handled | |
361 | else if ( !is_q_last | |
362 | && ip_info.is_qj // this check is redundant (also in is_spike_q) but faster | |
363 | && inters.i_info().count == 2 | |
364 | && inters.is_spike_q() ) | |
365 | { | |
366 | assign(pi, qi, inters.result(), ip_index, method, p_operation, operation_blocked, | |
367 | p_pos, q_pos, is_p_first_ip, is_q_first_ip, false, true, tp_model, out); | |
368 | assign(pi, qi, inters.result(), ip_index, method, p_operation, operation_intersection, | |
369 | p_pos, q_pos, is_p_first_ip, is_q_first_ip, false, true, tp_model, out); | |
370 | } | |
371 | // no spikes | |
372 | else | |
373 | { | |
374 | assign(pi, qi, inters.result(), ip_index, method, p_operation, q_operation, | |
375 | p_pos, q_pos, is_p_first_ip, is_q_first_ip, false, false, tp_model, out); | |
376 | } | |
377 | } | |
378 | } | |
379 | ||
380 | return append_last; | |
381 | } | |
382 | ||
383 | // TODO: IT'S ALSO PROBABLE THAT ALL THIS FUNCTION COULD BE INTEGRATED WITH handle_segment | |
384 | // however now it's lazily calculated and then it would be always calculated | |
385 | ||
386 | template<std::size_t G1Index, | |
387 | typename Point1, | |
388 | typename Point2, | |
389 | typename RobustPoint1, | |
390 | typename RobustPoint2, | |
391 | typename TurnInfo, | |
392 | typename IntersectionInfo | |
393 | > | |
394 | static inline bool handle_internal(Point1 const& /*i1*/, Point1 const& /*j1*/, Point1 const& /*k1*/, | |
395 | Point2 const& i2, Point2 const& j2, Point2 const& /*k2*/, | |
396 | RobustPoint1 const& ri1, RobustPoint1 const& rj1, RobustPoint1 const& /*rk1*/, | |
397 | RobustPoint2 const& ri2, RobustPoint2 const& rj2, RobustPoint2 const& rk2, | |
398 | bool first1, bool last1, bool first2, bool last2, | |
399 | bool ip_i2, bool ip_j2, TurnInfo const& tp_model, | |
400 | IntersectionInfo const& inters, unsigned int ip_index, | |
401 | operation_type & op1, operation_type & op2) | |
402 | { | |
403 | typedef typename cs_tag<typename TurnInfo::point_type>::type cs_tag; | |
404 | ||
405 | boost::ignore_unused_variable_warning(i2); | |
406 | boost::ignore_unused_variable_warning(j2); | |
407 | boost::ignore_unused_variable_warning(ip_index); | |
408 | boost::ignore_unused_variable_warning(tp_model); | |
409 | ||
410 | if ( !first2 && !last2 ) | |
411 | { | |
412 | if ( first1 ) | |
413 | { | |
414 | #ifdef BOOST_GEOMETRY_DEBUG_GET_TURNS_LINEAR_LINEAR | |
415 | // may this give false positives for INTs? | |
416 | typename IntersectionResult::point_type const& | |
417 | inters_pt = inters.i_info().intersections[ip_index]; | |
418 | BOOST_GEOMETRY_ASSERT(ip_i2 == equals::equals_point_point(i2, inters_pt)); | |
419 | BOOST_GEOMETRY_ASSERT(ip_j2 == equals::equals_point_point(j2, inters_pt)); | |
420 | #endif | |
421 | if ( ip_i2 ) | |
422 | { | |
423 | // don't output this IP - for the first point of other geometry segment | |
424 | op1 = operation_none; | |
425 | op2 = operation_none; | |
426 | return true; | |
427 | } | |
428 | else if ( ip_j2 ) | |
429 | { | |
430 | side_calculator<cs_tag, RobustPoint1, RobustPoint2, RobustPoint2> | |
431 | side_calc(ri2, ri1, rj1, ri2, rj2, rk2); | |
432 | ||
433 | std::pair<operation_type, operation_type> | |
434 | operations = operations_of_equal(side_calc); | |
435 | ||
436 | // TODO: must the above be calculated? | |
437 | // wouldn't it be enough to check if segments are collinear? | |
438 | ||
439 | if ( operations_both(operations, operation_continue) ) | |
440 | { | |
441 | if ( op1 != operation_union | |
442 | || op2 != operation_union | |
443 | || ! ( G1Index == 0 ? inters.is_spike_q() : inters.is_spike_p() ) ) | |
444 | { | |
445 | // THIS IS WRT THE ORIGINAL SEGMENTS! NOT THE ONES ABOVE! | |
446 | bool opposite = inters.d_info().opposite; | |
447 | ||
448 | op1 = operation_intersection; | |
449 | op2 = opposite ? operation_union : operation_intersection; | |
450 | } | |
451 | } | |
452 | else | |
453 | { | |
454 | BOOST_GEOMETRY_ASSERT(operations_combination(operations, operation_intersection, operation_union)); | |
455 | //op1 = operation_union; | |
456 | //op2 = operation_union; | |
457 | } | |
458 | ||
459 | return true; | |
460 | } | |
461 | // else do nothing - shouldn't be handled this way | |
462 | } | |
463 | else if ( last1 ) | |
464 | { | |
465 | #ifdef BOOST_GEOMETRY_DEBUG_GET_TURNS_LINEAR_LINEAR | |
466 | // may this give false positives for INTs? | |
467 | typename IntersectionResult::point_type const& | |
468 | inters_pt = inters.i_info().intersections[ip_index]; | |
469 | BOOST_GEOMETRY_ASSERT(ip_i2 == equals::equals_point_point(i2, inters_pt)); | |
470 | BOOST_GEOMETRY_ASSERT(ip_j2 == equals::equals_point_point(j2, inters_pt)); | |
471 | #endif | |
472 | if ( ip_i2 ) | |
473 | { | |
474 | // don't output this IP - for the first point of other geometry segment | |
475 | op1 = operation_none; | |
476 | op2 = operation_none; | |
477 | return true; | |
478 | } | |
479 | else if ( ip_j2 ) | |
480 | { | |
481 | side_calculator<cs_tag, RobustPoint1, RobustPoint2, RobustPoint2> | |
482 | side_calc(ri2, rj1, ri1, ri2, rj2, rk2); | |
483 | ||
484 | std::pair<operation_type, operation_type> | |
485 | operations = operations_of_equal(side_calc); | |
486 | ||
487 | // TODO: must the above be calculated? | |
488 | // wouldn't it be enough to check if segments are collinear? | |
489 | ||
490 | if ( operations_both(operations, operation_continue) ) | |
491 | { | |
492 | if ( op1 != operation_blocked | |
493 | || op2 != operation_union | |
494 | || ! ( G1Index == 0 ? inters.is_spike_q() : inters.is_spike_p() ) ) | |
495 | { | |
496 | // THIS IS WRT THE ORIGINAL SEGMENTS! NOT THE ONES ABOVE! | |
497 | bool second_going_out = inters.i_info().count > 1; | |
498 | ||
499 | op1 = operation_blocked; | |
500 | op2 = second_going_out ? operation_union : operation_intersection; | |
501 | } | |
502 | } | |
503 | else | |
504 | { | |
505 | BOOST_GEOMETRY_ASSERT(operations_combination(operations, operation_intersection, operation_union)); | |
506 | //op1 = operation_blocked; | |
507 | //op2 = operation_union; | |
508 | } | |
509 | ||
510 | return true; | |
511 | } | |
512 | // else do nothing - shouldn't be handled this way | |
513 | } | |
514 | // else do nothing - shouldn't be handled this way | |
515 | } | |
516 | ||
517 | return false; | |
518 | } | |
519 | ||
520 | static inline method_type endpoint_ip_method(bool ip_pi, bool ip_pj, bool ip_qi, bool ip_qj) | |
521 | { | |
522 | if ( (ip_pi || ip_pj) && (ip_qi || ip_qj) ) | |
523 | return method_touch; | |
524 | else | |
525 | return method_touch_interior; | |
526 | } | |
527 | ||
528 | static inline turn_position ip_position(bool is_ip_first_i, bool is_ip_last_j) | |
529 | { | |
530 | return is_ip_first_i ? position_front : | |
531 | ( is_ip_last_j ? position_back : position_middle ); | |
532 | } | |
533 | ||
534 | template <typename Point1, | |
535 | typename Point2, | |
536 | typename IntersectionResult, | |
537 | typename TurnInfo, | |
538 | typename OutputIterator> | |
539 | static inline void assign(Point1 const& pi, Point2 const& qi, | |
540 | IntersectionResult const& result, | |
541 | unsigned int ip_index, | |
542 | method_type method, | |
543 | operation_type op0, operation_type op1, | |
544 | turn_position pos0, turn_position pos1, | |
545 | bool is_p_first_ip, bool is_q_first_ip, | |
546 | bool is_p_spike, bool is_q_spike, | |
547 | TurnInfo const& tp_model, | |
548 | OutputIterator out) | |
549 | { | |
550 | TurnInfo tp = tp_model; | |
551 | ||
552 | //geometry::convert(ip, tp.point); | |
553 | //tp.method = method; | |
554 | base_turn_handler::assign_point(tp, method, result.template get<0>(), ip_index); | |
555 | ||
556 | tp.operations[0].operation = op0; | |
557 | tp.operations[1].operation = op1; | |
558 | tp.operations[0].position = pos0; | |
559 | tp.operations[1].position = pos1; | |
560 | ||
561 | if ( result.template get<0>().count > 1 ) | |
562 | { | |
563 | // NOTE: is_collinear is NOT set for the first endpoint | |
564 | // for which there is no preceding segment | |
565 | ||
566 | //BOOST_GEOMETRY_ASSERT( result.template get<1>().dir_a == 0 && result.template get<1>().dir_b == 0 ); | |
567 | if ( ! is_p_first_ip ) | |
568 | { | |
569 | tp.operations[0].is_collinear = op0 != operation_intersection | |
570 | || is_p_spike; | |
571 | } | |
572 | ||
573 | if ( ! is_q_first_ip ) | |
574 | { | |
575 | tp.operations[1].is_collinear = op1 != operation_intersection | |
576 | || is_q_spike; | |
577 | } | |
578 | } | |
579 | else //if ( result.template get<0>().count == 1 ) | |
580 | { | |
581 | if ( op0 == operation_blocked && op1 == operation_intersection ) | |
582 | { | |
583 | tp.operations[0].is_collinear = true; | |
584 | } | |
585 | else if ( op0 == operation_intersection && op1 == operation_blocked ) | |
586 | { | |
587 | tp.operations[1].is_collinear = true; | |
588 | } | |
589 | } | |
590 | ||
591 | // TODO: this should get an intersection_info, which is unavailable here | |
592 | // Because the assign_null policy accepts any structure, we pass the result instead for now | |
593 | AssignPolicy::apply(tp, pi, qi, result); | |
594 | *out++ = tp; | |
595 | } | |
596 | ||
597 | template <typename SidePolicy> | |
598 | static inline std::pair<operation_type, operation_type> operations_of_equal(SidePolicy const& side) | |
599 | { | |
600 | int const side_pk_q2 = side.pk_wrt_q2(); | |
601 | int const side_pk_p = side.pk_wrt_p1(); | |
602 | int const side_qk_p = side.qk_wrt_p1(); | |
603 | ||
604 | // If pk is collinear with qj-qk, they continue collinearly. | |
605 | // This can be on either side of p1 (== q1), or collinear | |
606 | // The second condition checks if they do not continue | |
607 | // oppositely | |
608 | if ( side_pk_q2 == 0 && side_pk_p == side_qk_p ) | |
609 | { | |
610 | return std::make_pair(operation_continue, operation_continue); | |
611 | } | |
612 | ||
613 | // If they turn to same side (not opposite sides) | |
614 | if ( ! base_turn_handler::opposite(side_pk_p, side_qk_p) ) | |
615 | { | |
616 | // If pk is left of q2 or collinear: p: union, q: intersection | |
617 | if ( side_pk_q2 != -1 ) | |
618 | { | |
619 | return std::make_pair(operation_union, operation_intersection); | |
620 | } | |
621 | else | |
622 | { | |
623 | return std::make_pair(operation_intersection, operation_union); | |
624 | } | |
625 | } | |
626 | else | |
627 | { | |
628 | // They turn opposite sides. If p turns left (or collinear), | |
629 | // p: union, q: intersection | |
630 | if ( side_pk_p != -1 ) | |
631 | { | |
632 | return std::make_pair(operation_union, operation_intersection); | |
633 | } | |
634 | else | |
635 | { | |
636 | return std::make_pair(operation_intersection, operation_union); | |
637 | } | |
638 | } | |
639 | } | |
640 | ||
641 | static inline bool operations_both( | |
642 | std::pair<operation_type, operation_type> const& operations, | |
643 | operation_type const op) | |
644 | { | |
645 | return operations.first == op && operations.second == op; | |
646 | } | |
647 | ||
648 | static inline bool operations_combination( | |
649 | std::pair<operation_type, operation_type> const& operations, | |
650 | operation_type const op1, operation_type const op2) | |
651 | { | |
652 | return ( operations.first == op1 && operations.second == op2 ) | |
653 | || ( operations.first == op2 && operations.second == op1 ); | |
654 | } | |
655 | }; | |
656 | ||
657 | }} // namespace detail::overlay | |
658 | #endif // DOXYGEN_NO_DETAIL | |
659 | ||
660 | }} // namespace boost::geometry | |
661 | ||
662 | #endif // BOOST_GEOMETRY_ALGORITHMS_DETAIL_OVERLAY_GET_TURN_INFO_FOR_ENDPOINT_HPP |