File indexing completed on 2025-01-18 09:35:10
0001
0002
0003
0004
0005
0006
0007
0008
0009
0010
0011
0012
0013
0014
0015 #ifndef BOOST_GEOMETRY_ALGORITHMS_DETAIL_OVERLAY_GET_TURN_INFO_LL_HPP
0016 #define BOOST_GEOMETRY_ALGORITHMS_DETAIL_OVERLAY_GET_TURN_INFO_LL_HPP
0017
0018 #include <boost/throw_exception.hpp>
0019
0020 #include <boost/geometry/core/assert.hpp>
0021
0022 #include <boost/geometry/algorithms/detail/overlay/get_turn_info.hpp>
0023 #include <boost/geometry/algorithms/detail/overlay/get_turn_info_for_endpoint.hpp>
0024
0025 #include <boost/geometry/util/condition.hpp>
0026
0027 namespace boost { namespace geometry {
0028
0029 #ifndef DOXYGEN_NO_DETAIL
0030 namespace detail { namespace overlay {
0031
0032 template<typename AssignPolicy>
0033 struct get_turn_info_linear_linear
0034 {
0035 static const bool handle_spikes = true;
0036
0037 template
0038 <
0039 typename UniqueSubRange1,
0040 typename UniqueSubRange2,
0041 typename TurnInfo,
0042 typename UmbrellaStrategy,
0043 typename RobustPolicy,
0044 typename OutputIterator
0045 >
0046 static inline OutputIterator apply(
0047 UniqueSubRange1 const& range_p,
0048 UniqueSubRange2 const& range_q,
0049 TurnInfo const& tp_model,
0050 UmbrellaStrategy const& umbrella_strategy,
0051 RobustPolicy const& robust_policy,
0052 OutputIterator out)
0053 {
0054 typedef intersection_info
0055 <
0056 UniqueSubRange1, UniqueSubRange2,
0057 typename TurnInfo::point_type,
0058 UmbrellaStrategy,
0059 RobustPolicy
0060 > inters_info;
0061
0062 inters_info inters(range_p, range_q, umbrella_strategy, robust_policy);
0063
0064 char const method = inters.d_info().how;
0065
0066
0067 TurnInfo tp = tp_model;
0068
0069
0070 switch(method)
0071 {
0072 case 'a' :
0073 case 'f' :
0074 case 's' :
0075 get_turn_info_for_endpoint<true, true>
0076 ::apply(range_p, range_q,
0077 tp_model, inters, method_none, out,
0078 umbrella_strategy);
0079 break;
0080
0081 case 'd' :
0082 break;
0083
0084 case 'm' :
0085 {
0086 using handler = touch_interior<TurnInfo, verify_policy_ll>;
0087
0088 if ( get_turn_info_for_endpoint<false, true>
0089 ::apply(range_p, range_q,
0090 tp_model, inters, method_touch_interior, out,
0091 umbrella_strategy) )
0092 {
0093
0094 }
0095 else
0096 {
0097
0098 if ( inters.d_info().arrival[1] == 1)
0099 {
0100 handler::template apply<0>(range_p, range_q, tp,
0101 inters.i_info(), inters.d_info(),
0102 inters.sides(),
0103 umbrella_strategy);
0104 }
0105 else
0106 {
0107
0108 handler::template apply<1>(range_q, range_p, tp,
0109 inters.i_info(), inters.d_info(),
0110 inters.swapped_sides(),
0111 umbrella_strategy);
0112 }
0113
0114 if ( tp.operations[0].operation == operation_blocked )
0115 {
0116 tp.operations[1].is_collinear = true;
0117 }
0118 if ( tp.operations[1].operation == operation_blocked )
0119 {
0120 tp.operations[0].is_collinear = true;
0121 }
0122
0123 replace_method_and_operations_tm(tp.method,
0124 tp.operations[0].operation,
0125 tp.operations[1].operation);
0126
0127 *out++ = tp;
0128 }
0129 }
0130 break;
0131 case 'i' :
0132 {
0133 crosses<TurnInfo>::apply(tp, inters.i_info(), inters.d_info());
0134
0135 replace_operations_i(tp.operations[0].operation, tp.operations[1].operation);
0136
0137 *out++ = tp;
0138 }
0139 break;
0140 case 't' :
0141 {
0142 using handler = touch<TurnInfo, verify_policy_ll>;
0143
0144
0145 if ( get_turn_info_for_endpoint<false, true>
0146 ::apply(range_p, range_q,
0147 tp_model, inters, method_touch, out,
0148 umbrella_strategy) )
0149 {
0150
0151 }
0152 else
0153 {
0154 handler::apply(range_p, range_q, tp,
0155 inters.i_info(), inters.d_info(),
0156 inters.sides(),
0157 umbrella_strategy);
0158
0159
0160
0161
0162
0163
0164
0165 if ( tp.operations[0].operation == operation_blocked
0166 && tp.operations[1].operation == operation_blocked )
0167 {
0168
0169 if ( inters.is_spike_p() && inters.is_spike_q() )
0170 {
0171 tp.operations[0].operation = operation_union;
0172 tp.operations[1].operation = operation_union;
0173 }
0174 else
0175 {
0176 tp.operations[0].is_collinear = true;
0177 tp.operations[1].is_collinear = true;
0178 }
0179 }
0180 else if ( tp.operations[0].operation == operation_blocked )
0181 {
0182
0183 if ( inters.is_spike_p() )
0184 {
0185 if ( inters.sides().qk_wrt_p1() == 0 )
0186 {
0187 tp.operations[0].is_collinear = true;
0188 }
0189 else
0190 {
0191 tp.operations[0].operation = operation_union;
0192 }
0193 }
0194 else
0195 {
0196 tp.operations[1].is_collinear = true;
0197 }
0198 }
0199 else if ( tp.operations[1].operation == operation_blocked )
0200 {
0201
0202 if ( inters.is_spike_q() )
0203 {
0204 if ( inters.sides().pk_wrt_q1() == 0 )
0205 {
0206 tp.operations[1].is_collinear = true;
0207 }
0208 else
0209 {
0210 tp.operations[1].operation = operation_union;
0211 }
0212 }
0213 else
0214 {
0215 tp.operations[0].is_collinear = true;
0216 }
0217 }
0218 else if ( tp.operations[0].operation == operation_continue
0219 && tp.operations[1].operation == operation_continue )
0220 {
0221
0222 if ( inters.sides().pk_wrt_q1() == -inters.sides().qk_wrt_q1()
0223 && inters.is_spike_p() )
0224 {
0225 tp.operations[0].operation = operation_union;
0226 tp.operations[1].operation = operation_union;
0227 }
0228 }
0229 else if ( tp.operations[0].operation == operation_none
0230 && tp.operations[1].operation == operation_none )
0231 {
0232
0233 bool const is_p = inters.is_spike_p();
0234 bool const is_q = inters.is_spike_q();
0235
0236 if ( is_p || is_q )
0237 {
0238 tp.operations[0].operation = operation_union;
0239 tp.operations[1].operation = operation_union;
0240
0241 if ( inters.sides().pk_wrt_q2() == 0 )
0242 {
0243 tp.operations[0].operation = operation_continue;
0244 if ( is_p )
0245 {
0246 tp.operations[0].is_collinear = true;
0247 }
0248 }
0249
0250 if ( inters.sides().qk_wrt_p2() == 0 )
0251 {
0252 tp.operations[1].operation = operation_continue;
0253 if ( is_q )
0254 {
0255 tp.operations[1].is_collinear = true;
0256 }
0257 }
0258 }
0259 }
0260
0261
0262
0263 replace_method_and_operations_tm(tp.method,
0264 tp.operations[0].operation,
0265 tp.operations[1].operation);
0266
0267 if ( ! BOOST_GEOMETRY_CONDITION(handle_spikes)
0268 || ! append_opposite_spikes<append_touches>(tp, inters, out) )
0269 {
0270 *out++ = tp;
0271 }
0272 }
0273 }
0274 break;
0275 case 'e':
0276 {
0277 using handler = equal<TurnInfo, verify_policy_ll>;
0278
0279 if ( get_turn_info_for_endpoint<true, true>
0280 ::apply(range_p, range_q,
0281 tp_model, inters, method_equal, out,
0282 umbrella_strategy) )
0283 {
0284
0285 }
0286 else
0287 {
0288 tp.operations[0].is_collinear = true;
0289 tp.operations[1].is_collinear = true;
0290
0291 if ( ! inters.d_info().opposite )
0292 {
0293
0294
0295 handler::apply(range_p, range_q, tp,
0296 inters.i_info(), inters.d_info(), inters.sides(),
0297 umbrella_strategy);
0298
0299 operation_type spike_op
0300 = ( tp.operations[0].operation != operation_continue
0301 || tp.operations[1].operation != operation_continue ) ?
0302 operation_union :
0303 operation_continue;
0304
0305
0306 turn_transformer_ec transformer(method_touch);
0307 transformer(tp);
0308
0309
0310 if ( ! BOOST_GEOMETRY_CONDITION(handle_spikes)
0311 || ! append_collinear_spikes(tp, inters,
0312 method_touch, spike_op,
0313 out) )
0314 {
0315 *out++ = tp;
0316 }
0317 }
0318 else
0319 {
0320
0321
0322 equal_opposite
0323 <
0324 TurnInfo,
0325 AssignPolicy
0326 >::apply(range_p, range_q, tp, out, inters);
0327 }
0328 }
0329 }
0330 break;
0331 case 'c' :
0332 {
0333
0334 if ( get_turn_info_for_endpoint<true, true>
0335 ::apply(range_p, range_q,
0336 tp_model, inters, method_collinear, out,
0337 umbrella_strategy) )
0338 {
0339
0340 }
0341 else
0342 {
0343
0344 tp.operations[0].is_collinear = true;
0345 tp.operations[1].is_collinear = true;
0346
0347 if ( ! inters.d_info().opposite )
0348 {
0349 method_type method_replace = method_touch_interior;
0350 operation_type spike_op = operation_continue;
0351
0352 if ( inters.d_info().arrival[0] == 0 )
0353 {
0354
0355 using handler = equal<TurnInfo, verify_policy_ll>;
0356
0357 handler::apply(range_p, range_q, tp,
0358 inters.i_info(), inters.d_info(), inters.sides(),
0359 umbrella_strategy);
0360
0361 method_replace = method_touch;
0362 if ( tp.operations[0].operation != operation_continue
0363 || tp.operations[1].operation != operation_continue )
0364 {
0365 spike_op = operation_union;
0366 }
0367 }
0368 else
0369 {
0370 using handler = collinear<TurnInfo, verify_policy_ll>;
0371 handler::apply(range_p, range_q, tp,
0372 inters.i_info(), inters.d_info(),
0373 inters.sides());
0374
0375
0376
0377 }
0378
0379
0380 turn_transformer_ec transformer(method_replace);
0381 transformer(tp);
0382
0383
0384 if ( ! BOOST_GEOMETRY_CONDITION(handle_spikes)
0385 || ! append_collinear_spikes(tp, inters,
0386 method_replace, spike_op,
0387 out) )
0388 {
0389
0390 *out++ = tp;
0391 }
0392 }
0393 else
0394 {
0395
0396 turn_transformer_ec transformer(method_touch_interior);
0397
0398
0399 if ( BOOST_GEOMETRY_CONDITION(handle_spikes) )
0400 {
0401 append_opposite_spikes<append_collinear_opposite>(tp, inters, out);
0402 }
0403
0404
0405
0406
0407
0408 collinear_opposite
0409 <
0410 TurnInfo,
0411 AssignPolicy
0412 >::apply(range_p, range_q,
0413 tp, out, inters, inters.sides(),
0414 transformer);
0415 }
0416 }
0417 }
0418 break;
0419 case '0' :
0420 {
0421
0422 if ( BOOST_GEOMETRY_CONDITION(AssignPolicy::include_degenerate) )
0423 {
0424 only_convert::apply(tp, inters.i_info());
0425
0426
0427 if ( range_p.is_first_segment()
0428 && equals::equals_point_point(range_p.at(0), tp.point, umbrella_strategy) )
0429 {
0430 tp.operations[0].position = position_front;
0431 }
0432 else if ( range_p.is_last_segment()
0433 && equals::equals_point_point(range_p.at(1), tp.point, umbrella_strategy) )
0434 {
0435 tp.operations[0].position = position_back;
0436 }
0437 else if ( range_q.is_first_segment()
0438 && equals::equals_point_point(range_q.at(0), tp.point, umbrella_strategy) )
0439 {
0440 tp.operations[1].position = position_front;
0441 }
0442 else if ( range_q.is_last_segment()
0443 && equals::equals_point_point(range_q.at(1), tp.point, umbrella_strategy) )
0444 {
0445 tp.operations[1].position = position_back;
0446 }
0447
0448 *out++ = tp;
0449 }
0450 }
0451 break;
0452 default :
0453 {
0454 #if defined(BOOST_GEOMETRY_DEBUG_ROBUSTNESS)
0455 std::cout << "TURN: Unknown method: " << method << std::endl;
0456 #endif
0457 #if ! defined(BOOST_GEOMETRY_OVERLAY_NO_THROW)
0458 BOOST_THROW_EXCEPTION(turn_info_exception(method));
0459 #endif
0460 }
0461 break;
0462 }
0463
0464 return out;
0465 }
0466
0467 template <typename TurnInfo,
0468 typename IntersectionInfo,
0469 typename OutIt>
0470 static inline bool append_collinear_spikes(TurnInfo & tp,
0471 IntersectionInfo const& inters_info,
0472 method_type method, operation_type spike_op,
0473 OutIt out)
0474 {
0475
0476
0477
0478 bool is_p_spike = tp.operations[0].operation == spike_op
0479 && inters_info.is_spike_p();
0480 bool is_q_spike = tp.operations[1].operation == spike_op
0481 && inters_info.is_spike_q();
0482
0483 if ( is_p_spike && is_q_spike )
0484 {
0485 if ( tp.method == method_equal
0486 && tp.operations[0].operation == operation_continue
0487 && tp.operations[1].operation == operation_continue )
0488 {
0489
0490 return false;
0491 }
0492
0493 tp.method = method;
0494 tp.operations[0].operation = operation_blocked;
0495 tp.operations[1].operation = operation_blocked;
0496 *out++ = tp;
0497 tp.operations[0].operation = operation_intersection;
0498 tp.operations[1].operation = operation_intersection;
0499 *out++ = tp;
0500
0501 return true;
0502 }
0503 else if ( is_p_spike )
0504 {
0505 tp.method = method;
0506 tp.operations[0].operation = operation_blocked;
0507 tp.operations[1].operation = operation_union;
0508 *out++ = tp;
0509 tp.operations[0].operation = operation_intersection;
0510
0511 *out++ = tp;
0512
0513 return true;
0514 }
0515 else if ( is_q_spike )
0516 {
0517 tp.method = method;
0518 tp.operations[0].operation = operation_union;
0519 tp.operations[1].operation = operation_blocked;
0520 *out++ = tp;
0521
0522 tp.operations[1].operation = operation_intersection;
0523 *out++ = tp;
0524
0525 return true;
0526 }
0527
0528 return false;
0529 }
0530
0531 enum append_version { append_touches, append_collinear_opposite };
0532
0533 template <append_version Version,
0534 typename TurnInfo,
0535 typename IntersectionInfo,
0536 typename OutIt>
0537 static inline bool append_opposite_spikes(TurnInfo & tp,
0538 IntersectionInfo const& inters,
0539 OutIt out)
0540 {
0541 static const bool is_version_touches = (Version == append_touches);
0542
0543 bool is_p_spike = ( is_version_touches ?
0544 ( tp.operations[0].operation == operation_continue
0545 || tp.operations[0].operation == operation_intersection ) :
0546 true )
0547 && inters.is_spike_p();
0548 bool is_q_spike = ( is_version_touches ?
0549 ( tp.operations[1].operation == operation_continue
0550 || tp.operations[1].operation == operation_intersection ) :
0551 true )
0552 && inters.is_spike_q();
0553
0554 bool res = false;
0555
0556 if ( is_p_spike
0557 && ( BOOST_GEOMETRY_CONDITION(is_version_touches)
0558 || inters.d_info().arrival[0] == 1 ) )
0559 {
0560 if ( BOOST_GEOMETRY_CONDITION(is_version_touches) )
0561 {
0562 tp.operations[0].is_collinear = true;
0563 tp.operations[1].is_collinear = false;
0564 tp.method = method_touch;
0565 }
0566 else
0567 {
0568 tp.operations[0].is_collinear = true;
0569 tp.operations[1].is_collinear = false;
0570
0571 BOOST_GEOMETRY_ASSERT(inters.i_info().count > 1);
0572
0573 base_turn_handler::assign_point(tp, method_touch_interior,
0574 inters.i_info(), 1);
0575 }
0576
0577 tp.operations[0].operation = operation_blocked;
0578 tp.operations[1].operation = operation_intersection;
0579 *out++ = tp;
0580 tp.operations[0].operation = operation_intersection;
0581
0582 *out++ = tp;
0583
0584 res = true;
0585 }
0586
0587 if ( is_q_spike
0588 && ( BOOST_GEOMETRY_CONDITION(is_version_touches)
0589 || inters.d_info().arrival[1] == 1 ) )
0590 {
0591 if ( BOOST_GEOMETRY_CONDITION(is_version_touches) )
0592 {
0593 tp.operations[0].is_collinear = false;
0594 tp.operations[1].is_collinear = true;
0595 tp.method = method_touch;
0596 }
0597 else
0598 {
0599 tp.operations[0].is_collinear = false;
0600 tp.operations[1].is_collinear = true;
0601
0602 BOOST_GEOMETRY_ASSERT(inters.i_info().count > 0);
0603
0604 base_turn_handler::assign_point(tp, method_touch_interior, inters.i_info(), 0);
0605 }
0606
0607 tp.operations[0].operation = operation_intersection;
0608 tp.operations[1].operation = operation_blocked;
0609 *out++ = tp;
0610
0611 tp.operations[1].operation = operation_intersection;
0612 *out++ = tp;
0613
0614 res = true;
0615 }
0616
0617 return res;
0618 }
0619
0620 static inline void replace_method_and_operations_tm(method_type & method,
0621 operation_type & op0,
0622 operation_type & op1)
0623 {
0624 if ( op0 == operation_blocked && op1 == operation_blocked )
0625 {
0626
0627 method = (method == method_touch ? method_equal : method_collinear);
0628 op0 = operation_continue;
0629 op1 = operation_continue;
0630 }
0631 else
0632 {
0633 if ( op0 == operation_continue || op0 == operation_blocked )
0634 {
0635 op0 = operation_intersection;
0636 }
0637 else if ( op0 == operation_intersection )
0638 {
0639 op0 = operation_union;
0640 }
0641
0642 if ( op1 == operation_continue || op1 == operation_blocked )
0643 {
0644 op1 = operation_intersection;
0645 }
0646 else if ( op1 == operation_intersection )
0647 {
0648 op1 = operation_union;
0649 }
0650
0651
0652 if ( method == method_error )
0653 {
0654 method = method_touch_interior;
0655 op0 = operation_union;
0656 op1 = operation_union;
0657 }
0658 }
0659 }
0660
0661 class turn_transformer_ec
0662 {
0663 public:
0664 explicit turn_transformer_ec(method_type method_t_or_m)
0665 : m_method(method_t_or_m)
0666 {}
0667
0668 template <typename Turn>
0669 void operator()(Turn & turn) const
0670 {
0671 operation_type & op0 = turn.operations[0].operation;
0672 operation_type & op1 = turn.operations[1].operation;
0673
0674 BOOST_GEOMETRY_ASSERT(op0 != operation_blocked || op1 != operation_blocked );
0675
0676 if ( op0 == operation_blocked )
0677 {
0678 op0 = operation_intersection;
0679 }
0680 else if ( op0 == operation_intersection )
0681 {
0682 op0 = operation_union;
0683 }
0684
0685 if ( op1 == operation_blocked )
0686 {
0687 op1 = operation_intersection;
0688 }
0689 else if ( op1 == operation_intersection )
0690 {
0691 op1 = operation_union;
0692 }
0693
0694 if ( op0 == operation_intersection || op0 == operation_union
0695 || op1 == operation_intersection || op1 == operation_union )
0696 {
0697 turn.method = m_method;
0698 }
0699
0700
0701
0702 turn.operations[0].is_collinear = op0 != operation_intersection;
0703 turn.operations[1].is_collinear = op1 != operation_intersection;
0704 }
0705
0706 private:
0707 method_type m_method;
0708 };
0709
0710 static inline void replace_operations_i(operation_type & op0, operation_type & op1)
0711 {
0712 if ( op0 == operation_intersection )
0713 {
0714 op0 = operation_union;
0715 }
0716
0717 if ( op1 == operation_intersection )
0718 {
0719 op1 = operation_union;
0720 }
0721 }
0722 };
0723
0724 }}
0725 #endif
0726
0727 }}
0728
0729 #endif