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, 2017. 6 // Modifications copyright (c) 2013-2017 Oracle and/or its affiliates. 7 8 // Contributed and/or modified by Adam Wulkiewicz, on behalf of Oracle 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_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> linear_intersections(Point1 const & pi,Point2 const & qi,IntersectionResult const & result,bool is_p_last,bool is_q_last)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 { ip_infoboost::geometry::detail::overlay::linear_intersections::ip_info181 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> get() const191 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) union_or_blocked_same_dirs(int arrival,bool is_last)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) union_or_blocked_different_dirs(int arrival,bool is_last)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 > applyboost::geometry::detail::overlay::get_turn_info_for_endpoint235 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 analyse_segment_and_assign_ipboost::geometry::detail::overlay::get_turn_info_for_endpoint287 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 > handle_internalboost::geometry::detail::overlay::get_turn_info_for_endpoint394 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, 431 RobustPoint1, RobustPoint2, 432 typename IntersectionInfo::side_strategy_type, 433 RobustPoint2> 434 side_calc(ri2, ri1, rj1, ri2, rj2, rk2, inters.get_side_strategy()); 435 436 std::pair<operation_type, operation_type> 437 operations = operations_of_equal(side_calc); 438 439 // TODO: must the above be calculated? 440 // wouldn't it be enough to check if segments are collinear? 441 442 if ( operations_both(operations, operation_continue) ) 443 { 444 if ( op1 != operation_union 445 || op2 != operation_union 446 || ! ( G1Index == 0 ? inters.is_spike_q() : inters.is_spike_p() ) ) 447 { 448 // THIS IS WRT THE ORIGINAL SEGMENTS! NOT THE ONES ABOVE! 449 bool opposite = inters.d_info().opposite; 450 451 op1 = operation_intersection; 452 op2 = opposite ? operation_union : operation_intersection; 453 } 454 } 455 else 456 { 457 BOOST_GEOMETRY_ASSERT(operations_combination(operations, operation_intersection, operation_union)); 458 //op1 = operation_union; 459 //op2 = operation_union; 460 } 461 462 return true; 463 } 464 // else do nothing - shouldn't be handled this way 465 } 466 else if ( last1 ) 467 { 468 #ifdef BOOST_GEOMETRY_DEBUG_GET_TURNS_LINEAR_LINEAR 469 // may this give false positives for INTs? 470 typename IntersectionResult::point_type const& 471 inters_pt = inters.i_info().intersections[ip_index]; 472 BOOST_GEOMETRY_ASSERT(ip_i2 == equals::equals_point_point(i2, inters_pt)); 473 BOOST_GEOMETRY_ASSERT(ip_j2 == equals::equals_point_point(j2, inters_pt)); 474 #endif 475 if ( ip_i2 ) 476 { 477 // don't output this IP - for the first point of other geometry segment 478 op1 = operation_none; 479 op2 = operation_none; 480 return true; 481 } 482 else if ( ip_j2 ) 483 { 484 side_calculator<cs_tag, RobustPoint1, RobustPoint2, 485 typename IntersectionInfo::side_strategy_type, 486 RobustPoint2> 487 side_calc(ri2, rj1, ri1, ri2, rj2, rk2, inters.get_side_strategy()); 488 489 std::pair<operation_type, operation_type> 490 operations = operations_of_equal(side_calc); 491 492 // TODO: must the above be calculated? 493 // wouldn't it be enough to check if segments are collinear? 494 495 if ( operations_both(operations, operation_continue) ) 496 { 497 if ( op1 != operation_blocked 498 || op2 != operation_union 499 || ! ( G1Index == 0 ? inters.is_spike_q() : inters.is_spike_p() ) ) 500 { 501 // THIS IS WRT THE ORIGINAL SEGMENTS! NOT THE ONES ABOVE! 502 bool second_going_out = inters.i_info().count > 1; 503 504 op1 = operation_blocked; 505 op2 = second_going_out ? operation_union : operation_intersection; 506 } 507 } 508 else 509 { 510 BOOST_GEOMETRY_ASSERT(operations_combination(operations, operation_intersection, operation_union)); 511 //op1 = operation_blocked; 512 //op2 = operation_union; 513 } 514 515 return true; 516 } 517 // else do nothing - shouldn't be handled this way 518 } 519 // else do nothing - shouldn't be handled this way 520 } 521 522 return false; 523 } 524 endpoint_ip_methodboost::geometry::detail::overlay::get_turn_info_for_endpoint525 static inline method_type endpoint_ip_method(bool ip_pi, bool ip_pj, bool ip_qi, bool ip_qj) 526 { 527 if ( (ip_pi || ip_pj) && (ip_qi || ip_qj) ) 528 return method_touch; 529 else 530 return method_touch_interior; 531 } 532 ip_positionboost::geometry::detail::overlay::get_turn_info_for_endpoint533 static inline turn_position ip_position(bool is_ip_first_i, bool is_ip_last_j) 534 { 535 return is_ip_first_i ? position_front : 536 ( is_ip_last_j ? position_back : position_middle ); 537 } 538 539 template <typename Point1, 540 typename Point2, 541 typename IntersectionResult, 542 typename TurnInfo, 543 typename OutputIterator> assignboost::geometry::detail::overlay::get_turn_info_for_endpoint544 static inline void assign(Point1 const& pi, Point2 const& qi, 545 IntersectionResult const& result, 546 unsigned int ip_index, 547 method_type method, 548 operation_type op0, operation_type op1, 549 turn_position pos0, turn_position pos1, 550 bool is_p_first_ip, bool is_q_first_ip, 551 bool is_p_spike, bool is_q_spike, 552 TurnInfo const& tp_model, 553 OutputIterator out) 554 { 555 TurnInfo tp = tp_model; 556 557 //geometry::convert(ip, tp.point); 558 //tp.method = method; 559 base_turn_handler::assign_point(tp, method, result.template get<0>(), ip_index); 560 561 tp.operations[0].operation = op0; 562 tp.operations[1].operation = op1; 563 tp.operations[0].position = pos0; 564 tp.operations[1].position = pos1; 565 566 if ( result.template get<0>().count > 1 ) 567 { 568 // NOTE: is_collinear is NOT set for the first endpoint 569 // for which there is no preceding segment 570 571 //BOOST_GEOMETRY_ASSERT( result.template get<1>().dir_a == 0 && result.template get<1>().dir_b == 0 ); 572 if ( ! is_p_first_ip ) 573 { 574 tp.operations[0].is_collinear = op0 != operation_intersection 575 || is_p_spike; 576 } 577 578 if ( ! is_q_first_ip ) 579 { 580 tp.operations[1].is_collinear = op1 != operation_intersection 581 || is_q_spike; 582 } 583 } 584 else //if ( result.template get<0>().count == 1 ) 585 { 586 if ( op0 == operation_blocked && op1 == operation_intersection ) 587 { 588 tp.operations[0].is_collinear = true; 589 } 590 else if ( op0 == operation_intersection && op1 == operation_blocked ) 591 { 592 tp.operations[1].is_collinear = true; 593 } 594 } 595 596 // TODO: this should get an intersection_info, which is unavailable here 597 // Because the assign_null policy accepts any structure, we pass the result instead for now 598 AssignPolicy::apply(tp, pi, qi, result); 599 *out++ = tp; 600 } 601 602 template <typename SidePolicy> operations_of_equalboost::geometry::detail::overlay::get_turn_info_for_endpoint603 static inline std::pair<operation_type, operation_type> operations_of_equal(SidePolicy const& side) 604 { 605 int const side_pk_q2 = side.pk_wrt_q2(); 606 int const side_pk_p = side.pk_wrt_p1(); 607 int const side_qk_p = side.qk_wrt_p1(); 608 609 // If pk is collinear with qj-qk, they continue collinearly. 610 // This can be on either side of p1 (== q1), or collinear 611 // The second condition checks if they do not continue 612 // oppositely 613 if ( side_pk_q2 == 0 && side_pk_p == side_qk_p ) 614 { 615 return std::make_pair(operation_continue, operation_continue); 616 } 617 618 // If they turn to same side (not opposite sides) 619 if ( ! base_turn_handler::opposite(side_pk_p, side_qk_p) ) 620 { 621 // If pk is left of q2 or collinear: p: union, q: intersection 622 if ( side_pk_q2 != -1 ) 623 { 624 return std::make_pair(operation_union, operation_intersection); 625 } 626 else 627 { 628 return std::make_pair(operation_intersection, operation_union); 629 } 630 } 631 else 632 { 633 // They turn opposite sides. If p turns left (or collinear), 634 // p: union, q: intersection 635 if ( side_pk_p != -1 ) 636 { 637 return std::make_pair(operation_union, operation_intersection); 638 } 639 else 640 { 641 return std::make_pair(operation_intersection, operation_union); 642 } 643 } 644 } 645 operations_bothboost::geometry::detail::overlay::get_turn_info_for_endpoint646 static inline bool operations_both( 647 std::pair<operation_type, operation_type> const& operations, 648 operation_type const op) 649 { 650 return operations.first == op && operations.second == op; 651 } 652 operations_combinationboost::geometry::detail::overlay::get_turn_info_for_endpoint653 static inline bool operations_combination( 654 std::pair<operation_type, operation_type> const& operations, 655 operation_type const op1, operation_type const op2) 656 { 657 return ( operations.first == op1 && operations.second == op2 ) 658 || ( operations.first == op2 && operations.second == op1 ); 659 } 660 }; 661 662 }} // namespace detail::overlay 663 #endif // DOXYGEN_NO_DETAIL 664 665 }} // namespace boost::geometry 666 667 #endif // BOOST_GEOMETRY_ALGORITHMS_DETAIL_OVERLAY_GET_TURN_INFO_FOR_ENDPOINT_HPP 668