]>
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, 2015. | |
6 | // Modifications copyright (c) 2013-2015 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_LL_HPP | |
15 | #define BOOST_GEOMETRY_ALGORITHMS_DETAIL_OVERLAY_GET_TURN_INFO_LL_HPP | |
16 | ||
17 | #include <boost/geometry/core/assert.hpp> | |
18 | ||
19 | #include <boost/geometry/algorithms/detail/overlay/get_turn_info.hpp> | |
20 | #include <boost/geometry/algorithms/detail/overlay/get_turn_info_for_endpoint.hpp> | |
21 | ||
22 | #include <boost/geometry/util/condition.hpp> | |
23 | ||
24 | namespace boost { namespace geometry { | |
25 | ||
26 | #ifndef DOXYGEN_NO_DETAIL | |
27 | namespace detail { namespace overlay { | |
28 | ||
29 | template<typename AssignPolicy> | |
30 | struct get_turn_info_linear_linear | |
31 | { | |
32 | static const bool handle_spikes = true; | |
33 | ||
34 | template | |
35 | < | |
36 | typename Point1, | |
37 | typename Point2, | |
38 | typename TurnInfo, | |
39 | typename RobustPolicy, | |
40 | typename OutputIterator | |
41 | > | |
42 | static inline OutputIterator apply( | |
43 | Point1 const& pi, Point1 const& pj, Point1 const& pk, | |
44 | Point2 const& qi, Point2 const& qj, Point2 const& qk, | |
45 | bool is_p_first, bool is_p_last, | |
46 | bool is_q_first, bool is_q_last, | |
47 | TurnInfo const& tp_model, | |
48 | RobustPolicy const& robust_policy, | |
49 | OutputIterator out) | |
50 | { | |
51 | typedef intersection_info<Point1, Point2, typename TurnInfo::point_type, RobustPolicy> | |
52 | inters_info; | |
53 | ||
54 | inters_info inters(pi, pj, pk, qi, qj, qk, robust_policy); | |
55 | ||
56 | char const method = inters.d_info().how; | |
57 | ||
58 | // Copy, to copy possibly extended fields | |
59 | TurnInfo tp = tp_model; | |
60 | ||
61 | // Select method and apply | |
62 | switch(method) | |
63 | { | |
64 | case 'a' : // collinear, "at" | |
65 | case 'f' : // collinear, "from" | |
66 | case 's' : // starts from the middle | |
67 | get_turn_info_for_endpoint<AssignPolicy, true, true> | |
68 | ::apply(pi, pj, pk, qi, qj, qk, | |
69 | is_p_first, is_p_last, is_q_first, is_q_last, | |
70 | tp_model, inters, method_none, out); | |
71 | break; | |
72 | ||
73 | case 'd' : // disjoint: never do anything | |
74 | break; | |
75 | ||
76 | case 'm' : | |
77 | { | |
78 | if ( get_turn_info_for_endpoint<AssignPolicy, false, true> | |
79 | ::apply(pi, pj, pk, qi, qj, qk, | |
80 | is_p_first, is_p_last, is_q_first, is_q_last, | |
81 | tp_model, inters, method_touch_interior, out) ) | |
82 | { | |
83 | // do nothing | |
84 | } | |
85 | else | |
86 | { | |
87 | typedef touch_interior | |
88 | < | |
89 | TurnInfo | |
90 | > policy; | |
91 | ||
92 | // If Q (1) arrives (1) | |
93 | if ( inters.d_info().arrival[1] == 1) | |
94 | { | |
95 | policy::template apply<0>(pi, pj, pk, qi, qj, qk, | |
96 | tp, inters.i_info(), inters.d_info(), | |
97 | inters.sides()); | |
98 | } | |
99 | else | |
100 | { | |
101 | // Swap p/q | |
102 | side_calculator | |
103 | < | |
104 | typename inters_info::cs_tag, | |
105 | typename inters_info::robust_point2_type, | |
106 | typename inters_info::robust_point1_type | |
107 | > swapped_side_calc(inters.rqi(), inters.rqj(), inters.rqk(), | |
108 | inters.rpi(), inters.rpj(), inters.rpk()); | |
109 | ||
110 | policy::template apply<1>(qi, qj, qk, pi, pj, pk, | |
111 | tp, inters.i_info(), inters.d_info(), | |
112 | swapped_side_calc); | |
113 | } | |
114 | ||
115 | if ( tp.operations[0].operation == operation_blocked ) | |
116 | { | |
117 | tp.operations[1].is_collinear = true; | |
118 | } | |
119 | if ( tp.operations[1].operation == operation_blocked ) | |
120 | { | |
121 | tp.operations[0].is_collinear = true; | |
122 | } | |
123 | ||
124 | replace_method_and_operations_tm(tp.method, | |
125 | tp.operations[0].operation, | |
126 | tp.operations[1].operation); | |
127 | ||
128 | AssignPolicy::apply(tp, pi, qi, inters); | |
129 | *out++ = tp; | |
130 | } | |
131 | } | |
132 | break; | |
133 | case 'i' : | |
134 | { | |
135 | crosses<TurnInfo>::apply(pi, pj, pk, qi, qj, qk, | |
136 | tp, inters.i_info(), inters.d_info()); | |
137 | ||
138 | replace_operations_i(tp.operations[0].operation, tp.operations[1].operation); | |
139 | ||
140 | AssignPolicy::apply(tp, pi, qi, inters); | |
141 | *out++ = tp; | |
142 | } | |
143 | break; | |
144 | case 't' : | |
145 | { | |
146 | // Both touch (both arrive there) | |
147 | if ( get_turn_info_for_endpoint<AssignPolicy, false, true> | |
148 | ::apply(pi, pj, pk, qi, qj, qk, | |
149 | is_p_first, is_p_last, is_q_first, is_q_last, | |
150 | tp_model, inters, method_touch, out) ) | |
151 | { | |
152 | // do nothing | |
153 | } | |
154 | else | |
155 | { | |
156 | touch<TurnInfo>::apply(pi, pj, pk, qi, qj, qk, | |
157 | tp, inters.i_info(), inters.d_info(), inters.sides()); | |
158 | ||
159 | // workarounds for touch<> not taking spikes into account starts here | |
160 | // those was discovered empirically | |
161 | // touch<> is not symmetrical! | |
162 | // P spikes and Q spikes may produce various operations! | |
163 | // TODO: this is not optimal solution - think about rewriting touch<> | |
164 | ||
165 | if ( tp.operations[0].operation == operation_blocked | |
166 | && tp.operations[1].operation == operation_blocked ) | |
167 | { | |
168 | // two touching spikes on the same line | |
169 | if ( inters.is_spike_p() && inters.is_spike_q() ) | |
170 | { | |
171 | tp.operations[0].operation = operation_union; | |
172 | tp.operations[1].operation = operation_union; | |
173 | } | |
174 | else | |
175 | { | |
176 | tp.operations[0].is_collinear = true; | |
177 | tp.operations[1].is_collinear = true; | |
178 | } | |
179 | } | |
180 | else if ( tp.operations[0].operation == operation_blocked ) | |
181 | { | |
182 | // a spike on P on the same line with Q1 | |
183 | if ( inters.is_spike_p() ) | |
184 | { | |
185 | if ( inters.sides().qk_wrt_p1() == 0 ) | |
186 | { | |
187 | tp.operations[0].is_collinear = true; | |
188 | } | |
189 | else | |
190 | { | |
191 | tp.operations[0].operation = operation_union; | |
192 | } | |
193 | } | |
194 | else | |
195 | { | |
196 | tp.operations[1].is_collinear = true; | |
197 | } | |
198 | } | |
199 | else if ( tp.operations[1].operation == operation_blocked ) | |
200 | { | |
201 | // a spike on Q on the same line with P1 | |
202 | if ( inters.is_spike_q() ) | |
203 | { | |
204 | if ( inters.sides().pk_wrt_q1() == 0 ) | |
205 | { | |
206 | tp.operations[1].is_collinear = true; | |
207 | } | |
208 | else | |
209 | { | |
210 | tp.operations[1].operation = operation_union; | |
211 | } | |
212 | } | |
213 | else | |
214 | { | |
215 | tp.operations[0].is_collinear = true; | |
216 | } | |
217 | } | |
218 | else if ( tp.operations[0].operation == operation_continue | |
219 | && tp.operations[1].operation == operation_continue ) | |
220 | { | |
221 | // P spike on the same line with Q2 (opposite) | |
222 | if ( inters.sides().pk_wrt_q1() == -inters.sides().qk_wrt_q1() | |
223 | && inters.is_spike_p() ) | |
224 | { | |
225 | tp.operations[0].operation = operation_union; | |
226 | tp.operations[1].operation = operation_union; | |
227 | } | |
228 | } | |
229 | else if ( tp.operations[0].operation == operation_none | |
230 | && tp.operations[1].operation == operation_none ) | |
231 | { | |
232 | // spike not handled by touch<> | |
233 | bool const is_p = inters.is_spike_p(); | |
234 | bool const is_q = inters.is_spike_q(); | |
235 | ||
236 | if ( is_p || is_q ) | |
237 | { | |
238 | tp.operations[0].operation = operation_union; | |
239 | tp.operations[1].operation = operation_union; | |
240 | ||
241 | if ( inters.sides().pk_wrt_q2() == 0 ) | |
242 | { | |
243 | tp.operations[0].operation = operation_continue; // will be converted to i | |
244 | if ( is_p ) | |
245 | { | |
246 | tp.operations[0].is_collinear = true; | |
247 | } | |
248 | } | |
249 | ||
250 | if ( inters.sides().qk_wrt_p2() == 0 ) | |
251 | { | |
252 | tp.operations[1].operation = operation_continue; // will be converted to i | |
253 | if ( is_q ) | |
254 | { | |
255 | tp.operations[1].is_collinear = true; | |
256 | } | |
257 | } | |
258 | } | |
259 | } | |
260 | ||
261 | // workarounds for touch<> not taking spikes into account ends here | |
262 | ||
263 | replace_method_and_operations_tm(tp.method, | |
264 | tp.operations[0].operation, | |
265 | tp.operations[1].operation); | |
266 | ||
267 | // TODO: move this into the append_xxx and call for each turn? | |
268 | AssignPolicy::apply(tp, pi, qi, inters); | |
269 | ||
270 | if ( ! BOOST_GEOMETRY_CONDITION(handle_spikes) | |
271 | || ! append_opposite_spikes<append_touches>(tp, inters, | |
272 | is_p_last, is_q_last, | |
273 | out) ) | |
274 | { | |
275 | *out++ = tp; | |
276 | } | |
277 | } | |
278 | } | |
279 | break; | |
280 | case 'e': | |
281 | { | |
282 | if ( get_turn_info_for_endpoint<AssignPolicy, true, true> | |
283 | ::apply(pi, pj, pk, qi, qj, qk, | |
284 | is_p_first, is_p_last, is_q_first, is_q_last, | |
285 | tp_model, inters, method_equal, out) ) | |
286 | { | |
287 | // do nothing | |
288 | } | |
289 | else | |
290 | { | |
291 | tp.operations[0].is_collinear = true; | |
292 | tp.operations[1].is_collinear = true; | |
293 | ||
294 | if ( ! inters.d_info().opposite ) | |
295 | { | |
296 | // Both equal | |
297 | // or collinear-and-ending at intersection point | |
298 | equal<TurnInfo>::apply(pi, pj, pk, qi, qj, qk, | |
299 | tp, inters.i_info(), inters.d_info(), inters.sides()); | |
300 | ||
301 | operation_type spike_op | |
302 | = ( tp.operations[0].operation != operation_continue | |
303 | || tp.operations[1].operation != operation_continue ) ? | |
304 | operation_union : | |
305 | operation_continue; | |
306 | ||
307 | // transform turn | |
308 | turn_transformer_ec transformer(method_touch); | |
309 | transformer(tp); | |
310 | ||
311 | // TODO: move this into the append_xxx and call for each turn? | |
312 | AssignPolicy::apply(tp, pi, qi, inters); | |
313 | ||
314 | // conditionally handle spikes | |
315 | if ( ! BOOST_GEOMETRY_CONDITION(handle_spikes) | |
316 | || ! append_collinear_spikes(tp, inters, | |
317 | is_p_last, is_q_last, | |
318 | method_touch, spike_op, | |
319 | out) ) | |
320 | { | |
321 | *out++ = tp; // no spikes | |
322 | } | |
323 | } | |
324 | else | |
325 | { | |
326 | // TODO: ignore for spikes or generate something else than opposite? | |
327 | ||
328 | equal_opposite | |
329 | < | |
330 | TurnInfo, | |
331 | AssignPolicy | |
332 | >::apply(pi, qi, tp, out, inters); | |
333 | } | |
334 | } | |
335 | } | |
336 | break; | |
337 | case 'c' : | |
338 | { | |
339 | // Collinear | |
340 | if ( get_turn_info_for_endpoint<AssignPolicy, true, true> | |
341 | ::apply(pi, pj, pk, qi, qj, qk, | |
342 | is_p_first, is_p_last, is_q_first, is_q_last, | |
343 | tp_model, inters, method_collinear, out) ) | |
344 | { | |
345 | // do nothing | |
346 | } | |
347 | else | |
348 | { | |
349 | // NOTE: this is for spikes since those are set in the turn_transformer_ec | |
350 | tp.operations[0].is_collinear = true; | |
351 | tp.operations[1].is_collinear = true; | |
352 | ||
353 | if ( ! inters.d_info().opposite ) | |
354 | { | |
355 | method_type method_replace = method_touch_interior; | |
356 | operation_type spike_op = operation_continue; | |
357 | ||
358 | if ( inters.d_info().arrival[0] == 0 ) | |
359 | { | |
360 | // Collinear, but similar thus handled as equal | |
361 | equal<TurnInfo>::apply(pi, pj, pk, qi, qj, qk, | |
362 | tp, inters.i_info(), inters.d_info(), inters.sides()); | |
363 | ||
364 | method_replace = method_touch; | |
365 | if ( tp.operations[0].operation != operation_continue | |
366 | || tp.operations[1].operation != operation_continue ) | |
367 | { | |
368 | spike_op = operation_union; | |
369 | } | |
370 | } | |
371 | else | |
372 | { | |
373 | collinear<TurnInfo>::apply(pi, pj, pk, qi, qj, qk, | |
374 | tp, inters.i_info(), inters.d_info(), inters.sides()); | |
375 | ||
376 | //method_replace = method_touch_interior; | |
377 | //spike_op = operation_continue; | |
378 | } | |
379 | ||
380 | // transform turn | |
381 | turn_transformer_ec transformer(method_replace); | |
382 | transformer(tp); | |
383 | ||
384 | // TODO: move this into the append_xxx and call for each turn? | |
385 | AssignPolicy::apply(tp, pi, qi, inters); | |
386 | ||
387 | // conditionally handle spikes | |
388 | if ( ! BOOST_GEOMETRY_CONDITION(handle_spikes) | |
389 | || ! append_collinear_spikes(tp, inters, | |
390 | is_p_last, is_q_last, | |
391 | method_replace, spike_op, | |
392 | out) ) | |
393 | { | |
394 | // no spikes | |
395 | *out++ = tp; | |
396 | } | |
397 | } | |
398 | else | |
399 | { | |
400 | // If this always 'm' ? | |
401 | turn_transformer_ec transformer(method_touch_interior); | |
402 | ||
403 | // conditionally handle spikes | |
404 | if ( BOOST_GEOMETRY_CONDITION(handle_spikes) ) | |
405 | { | |
406 | append_opposite_spikes<append_collinear_opposite>(tp, inters, | |
407 | is_p_last, is_q_last, | |
408 | out); | |
409 | } | |
410 | ||
411 | // TODO: ignore for spikes? | |
412 | // E.g. pass is_p_valid = !is_p_last && !is_pj_spike, | |
413 | // the same with is_q_valid | |
414 | ||
415 | collinear_opposite | |
416 | < | |
417 | TurnInfo, | |
418 | AssignPolicy | |
419 | >::apply(pi, pj, pk, qi, qj, qk, | |
420 | tp, out, inters, inters.sides(), | |
421 | transformer, !is_p_last, !is_q_last); | |
422 | } | |
423 | } | |
424 | } | |
425 | break; | |
426 | case '0' : | |
427 | { | |
428 | // degenerate points | |
429 | if ( BOOST_GEOMETRY_CONDITION(AssignPolicy::include_degenerate) ) | |
430 | { | |
431 | only_convert::apply(tp, inters.i_info()); | |
432 | ||
433 | // if any, only one of those should be true | |
434 | if ( is_p_first | |
435 | && equals::equals_point_point(pi, tp.point) ) | |
436 | { | |
437 | tp.operations[0].position = position_front; | |
438 | } | |
439 | else if ( is_p_last | |
440 | && equals::equals_point_point(pj, tp.point) ) | |
441 | { | |
442 | tp.operations[0].position = position_back; | |
443 | } | |
444 | else if ( is_q_first | |
445 | && equals::equals_point_point(qi, tp.point) ) | |
446 | { | |
447 | tp.operations[1].position = position_front; | |
448 | } | |
449 | else if ( is_q_last | |
450 | && equals::equals_point_point(qj, tp.point) ) | |
451 | { | |
452 | tp.operations[1].position = position_back; | |
453 | } | |
454 | ||
455 | AssignPolicy::apply(tp, pi, qi, inters); | |
456 | *out++ = tp; | |
457 | } | |
458 | } | |
459 | break; | |
460 | default : | |
461 | { | |
462 | #if defined(BOOST_GEOMETRY_DEBUG_ROBUSTNESS) | |
463 | std::cout << "TURN: Unknown method: " << method << std::endl; | |
464 | #endif | |
465 | #if ! defined(BOOST_GEOMETRY_OVERLAY_NO_THROW) | |
466 | throw turn_info_exception(method); | |
467 | #endif | |
468 | } | |
469 | break; | |
470 | } | |
471 | ||
472 | return out; | |
473 | } | |
474 | ||
475 | template <typename TurnInfo, | |
476 | typename IntersectionInfo, | |
477 | typename OutIt> | |
478 | static inline bool append_collinear_spikes(TurnInfo & tp, | |
479 | IntersectionInfo const& inters_info, | |
480 | bool is_p_last, bool is_q_last, | |
481 | method_type method, operation_type spike_op, | |
482 | OutIt out) | |
483 | { | |
484 | // method == touch || touch_interior | |
485 | // both position == middle | |
486 | ||
487 | bool is_p_spike = tp.operations[0].operation == spike_op | |
488 | && ! is_p_last | |
489 | && inters_info.is_spike_p(); | |
490 | bool is_q_spike = tp.operations[1].operation == spike_op | |
491 | && ! is_q_last | |
492 | && inters_info.is_spike_q(); | |
493 | ||
494 | if ( is_p_spike && is_q_spike ) | |
495 | { | |
496 | if ( tp.method == method_equal | |
497 | && tp.operations[0].operation == operation_continue | |
498 | && tp.operations[1].operation == operation_continue ) | |
499 | { | |
500 | // treat both non-opposite collinear spikes as no-spikes | |
501 | return false; | |
502 | } | |
503 | ||
504 | tp.method = method; | |
505 | tp.operations[0].operation = operation_blocked; | |
506 | tp.operations[1].operation = operation_blocked; | |
507 | *out++ = tp; | |
508 | tp.operations[0].operation = operation_intersection; | |
509 | tp.operations[1].operation = operation_intersection; | |
510 | *out++ = tp; | |
511 | ||
512 | return true; | |
513 | } | |
514 | else if ( is_p_spike ) | |
515 | { | |
516 | tp.method = method; | |
517 | tp.operations[0].operation = operation_blocked; | |
518 | tp.operations[1].operation = operation_union; | |
519 | *out++ = tp; | |
520 | tp.operations[0].operation = operation_intersection; | |
521 | //tp.operations[1].operation = operation_union; | |
522 | *out++ = tp; | |
523 | ||
524 | return true; | |
525 | } | |
526 | else if ( is_q_spike ) | |
527 | { | |
528 | tp.method = method; | |
529 | tp.operations[0].operation = operation_union; | |
530 | tp.operations[1].operation = operation_blocked; | |
531 | *out++ = tp; | |
532 | //tp.operations[0].operation = operation_union; | |
533 | tp.operations[1].operation = operation_intersection; | |
534 | *out++ = tp; | |
535 | ||
536 | return true; | |
537 | } | |
538 | ||
539 | return false; | |
540 | } | |
541 | ||
542 | enum append_version { append_touches, append_collinear_opposite }; | |
543 | ||
544 | template <append_version Version, | |
545 | typename TurnInfo, | |
546 | typename IntersectionInfo, | |
547 | typename OutIt> | |
548 | static inline bool append_opposite_spikes(TurnInfo & tp, | |
549 | IntersectionInfo const& inters, | |
550 | bool is_p_last, bool is_q_last, | |
551 | OutIt out) | |
552 | { | |
553 | static const bool is_version_touches = (Version == append_touches); | |
554 | ||
555 | bool is_p_spike = ( is_version_touches ? | |
556 | ( tp.operations[0].operation == operation_continue | |
557 | || tp.operations[0].operation == operation_intersection ) : | |
558 | true ) | |
559 | && ! is_p_last | |
560 | && inters.is_spike_p(); | |
561 | bool is_q_spike = ( is_version_touches ? | |
562 | ( tp.operations[1].operation == operation_continue | |
563 | || tp.operations[1].operation == operation_intersection ) : | |
564 | true ) | |
565 | && ! is_q_last | |
566 | && inters.is_spike_q(); | |
567 | ||
568 | bool res = false; | |
569 | ||
570 | if ( is_p_spike | |
571 | && ( BOOST_GEOMETRY_CONDITION(is_version_touches) | |
572 | || inters.d_info().arrival[0] == 1 ) ) | |
573 | { | |
574 | if ( BOOST_GEOMETRY_CONDITION(is_version_touches) ) | |
575 | { | |
576 | tp.operations[0].is_collinear = true; | |
577 | tp.operations[1].is_collinear = false; | |
578 | tp.method = method_touch; | |
579 | } | |
580 | else // Version == append_collinear_opposite | |
581 | { | |
582 | tp.operations[0].is_collinear = true; | |
583 | tp.operations[1].is_collinear = false; | |
584 | ||
585 | BOOST_GEOMETRY_ASSERT(inters.i_info().count > 1); | |
586 | ||
587 | base_turn_handler::assign_point(tp, method_touch_interior, | |
588 | inters.i_info(), 1); | |
589 | ||
590 | AssignPolicy::apply(tp, inters.pi(), inters.qi(), inters); | |
591 | } | |
592 | ||
593 | tp.operations[0].operation = operation_blocked; | |
594 | tp.operations[1].operation = operation_intersection; | |
595 | *out++ = tp; | |
596 | tp.operations[0].operation = operation_intersection; | |
597 | //tp.operations[1].operation = operation_intersection; | |
598 | *out++ = tp; | |
599 | ||
600 | res = true; | |
601 | } | |
602 | ||
603 | if ( is_q_spike | |
604 | && ( BOOST_GEOMETRY_CONDITION(is_version_touches) | |
605 | || inters.d_info().arrival[1] == 1 ) ) | |
606 | { | |
607 | if ( BOOST_GEOMETRY_CONDITION(is_version_touches) ) | |
608 | { | |
609 | tp.operations[0].is_collinear = false; | |
610 | tp.operations[1].is_collinear = true; | |
611 | tp.method = method_touch; | |
612 | } | |
613 | else // Version == append_collinear_opposite | |
614 | { | |
615 | tp.operations[0].is_collinear = false; | |
616 | tp.operations[1].is_collinear = true; | |
617 | ||
618 | BOOST_GEOMETRY_ASSERT(inters.i_info().count > 0); | |
619 | ||
620 | base_turn_handler::assign_point(tp, method_touch_interior, inters.i_info(), 0); | |
621 | ||
622 | AssignPolicy::apply(tp, inters.pi(), inters.qi(), inters); | |
623 | } | |
624 | ||
625 | tp.operations[0].operation = operation_intersection; | |
626 | tp.operations[1].operation = operation_blocked; | |
627 | *out++ = tp; | |
628 | //tp.operations[0].operation = operation_intersection; | |
629 | tp.operations[1].operation = operation_intersection; | |
630 | *out++ = tp; | |
631 | ||
632 | res = true; | |
633 | } | |
634 | ||
635 | return res; | |
636 | } | |
637 | ||
638 | static inline void replace_method_and_operations_tm(method_type & method, | |
639 | operation_type & op0, | |
640 | operation_type & op1) | |
641 | { | |
642 | if ( op0 == operation_blocked && op1 == operation_blocked ) | |
643 | { | |
644 | // NOTE: probably only if methods are WRT IPs, not segments! | |
645 | method = (method == method_touch ? method_equal : method_collinear); | |
646 | op0 = operation_continue; | |
647 | op1 = operation_continue; | |
648 | } | |
649 | else | |
650 | { | |
651 | if ( op0 == operation_continue || op0 == operation_blocked ) | |
652 | { | |
653 | op0 = operation_intersection; | |
654 | } | |
655 | else if ( op0 == operation_intersection ) | |
656 | { | |
657 | op0 = operation_union; | |
658 | } | |
659 | ||
660 | if ( op1 == operation_continue || op1 == operation_blocked ) | |
661 | { | |
662 | op1 = operation_intersection; | |
663 | } | |
664 | else if ( op1 == operation_intersection ) | |
665 | { | |
666 | op1 = operation_union; | |
667 | } | |
668 | ||
669 | // spikes in 'm' | |
670 | if ( method == method_error ) | |
671 | { | |
672 | method = method_touch_interior; | |
673 | op0 = operation_union; | |
674 | op1 = operation_union; | |
675 | } | |
676 | } | |
677 | } | |
678 | ||
679 | class turn_transformer_ec | |
680 | { | |
681 | public: | |
682 | explicit turn_transformer_ec(method_type method_t_or_m) | |
683 | : m_method(method_t_or_m) | |
684 | {} | |
685 | ||
686 | template <typename Turn> | |
687 | void operator()(Turn & turn) const | |
688 | { | |
689 | operation_type & op0 = turn.operations[0].operation; | |
690 | operation_type & op1 = turn.operations[1].operation; | |
691 | ||
692 | BOOST_GEOMETRY_ASSERT(op0 != operation_blocked || op1 != operation_blocked ); | |
693 | ||
694 | if ( op0 == operation_blocked ) | |
695 | { | |
696 | op0 = operation_intersection; | |
697 | } | |
698 | else if ( op0 == operation_intersection ) | |
699 | { | |
700 | op0 = operation_union; | |
701 | } | |
702 | ||
703 | if ( op1 == operation_blocked ) | |
704 | { | |
705 | op1 = operation_intersection; | |
706 | } | |
707 | else if ( op1 == operation_intersection ) | |
708 | { | |
709 | op1 = operation_union; | |
710 | } | |
711 | ||
712 | if ( op0 == operation_intersection || op0 == operation_union | |
713 | || op1 == operation_intersection || op1 == operation_union ) | |
714 | { | |
715 | turn.method = m_method; | |
716 | } | |
717 | ||
718 | // TODO: is this correct? | |
719 | // it's equivalent to comparing to operation_blocked at the beginning of the function | |
720 | turn.operations[0].is_collinear = op0 != operation_intersection; | |
721 | turn.operations[1].is_collinear = op1 != operation_intersection; | |
722 | } | |
723 | ||
724 | private: | |
725 | method_type m_method; | |
726 | }; | |
727 | ||
728 | static inline void replace_operations_i(operation_type & op0, operation_type & op1) | |
729 | { | |
730 | if ( op0 == operation_intersection ) | |
731 | { | |
732 | op0 = operation_union; | |
733 | } | |
734 | ||
735 | if ( op1 == operation_intersection ) | |
736 | { | |
737 | op1 = operation_union; | |
738 | } | |
739 | } | |
740 | }; | |
741 | ||
742 | }} // namespace detail::overlay | |
743 | #endif // DOXYGEN_NO_DETAIL | |
744 | ||
745 | }} // namespace boost::geometry | |
746 | ||
747 | #endif // BOOST_GEOMETRY_ALGORITHMS_DETAIL_OVERLAY_GET_TURN_INFO_LL_HPP |