File indexing completed on 2025-01-18 09:35:09
0001
0002
0003
0004
0005
0006
0007
0008
0009
0010
0011
0012
0013
0014 #ifndef BOOST_GEOMETRY_ALGORITHMS_DETAIL_OVERLAY_GET_TURN_INFO_HPP
0015 #define BOOST_GEOMETRY_ALGORITHMS_DETAIL_OVERLAY_GET_TURN_INFO_HPP
0016
0017 #include <boost/core/ignore_unused.hpp>
0018 #include <boost/throw_exception.hpp>
0019
0020 #include <boost/geometry/core/access.hpp>
0021 #include <boost/geometry/core/assert.hpp>
0022 #include <boost/geometry/core/config.hpp>
0023 #include <boost/geometry/core/exception.hpp>
0024
0025 #include <boost/geometry/algorithms/convert.hpp>
0026 #include <boost/geometry/algorithms/detail/overlay/get_distance_measure.hpp>
0027 #include <boost/geometry/algorithms/detail/overlay/turn_info.hpp>
0028 #include <boost/geometry/algorithms/detail/overlay/get_turn_info_helpers.hpp>
0029
0030 #include <boost/geometry/util/condition.hpp>
0031
0032
0033 namespace boost { namespace geometry
0034 {
0035
0036 #if ! defined(BOOST_GEOMETRY_OVERLAY_NO_THROW)
0037 class turn_info_exception : public geometry::exception
0038 {
0039 std::string message;
0040 public:
0041
0042
0043 inline turn_info_exception(char const method)
0044 {
0045 message = "Boost.Geometry Turn exception: ";
0046 message += method;
0047 }
0048
0049 virtual char const* What() const noexcept
0050 {
0051 return message.c_str();
0052 }
0053 };
0054 #endif
0055
0056 #ifndef DOXYGEN_NO_DETAIL
0057 namespace detail { namespace overlay
0058 {
0059
0060
0061 struct policy_verify_nothing
0062 {
0063 static bool const use_side_verification = false;
0064 static bool const use_start_turn = false;
0065 static bool const use_handle_as_touch = false;
0066 static bool const use_handle_as_equal = false;
0067 static bool const use_handle_imperfect_touch = false;
0068 };
0069
0070 struct policy_verify_all
0071 {
0072 static bool const use_side_verification = true;
0073 static bool const use_start_turn = true;
0074 static bool const use_handle_as_touch = true;
0075 static bool const use_handle_as_equal = true;
0076 static bool const use_handle_imperfect_touch = true;
0077 };
0078
0079
0080 #if defined(BOOST_GEOMETRY_USE_RESCALING)
0081 using verify_policy_aa = policy_verify_nothing;
0082 #else
0083 using verify_policy_aa = policy_verify_all;
0084 #endif
0085
0086 using verify_policy_ll = policy_verify_nothing;
0087 using verify_policy_la = policy_verify_nothing;
0088
0089
0090 struct base_turn_handler
0091 {
0092
0093 static inline bool opposite(int side1, int side2)
0094 {
0095
0096
0097 return side1 * side2 == -1;
0098 }
0099
0100
0101 static inline bool same(int side1, int side2)
0102 {
0103 return side1 * side2 == 1;
0104 }
0105
0106
0107 template <typename TurnInfo>
0108 static inline void both(TurnInfo& ti, operation_type const op)
0109 {
0110 ti.operations[0].operation = op;
0111 ti.operations[1].operation = op;
0112 }
0113
0114
0115 template <typename TurnInfo>
0116 static inline void ui_else_iu(bool condition, TurnInfo& ti)
0117 {
0118 ti.operations[0].operation = condition
0119 ? operation_union : operation_intersection;
0120 ti.operations[1].operation = condition
0121 ? operation_intersection : operation_union;
0122 }
0123
0124
0125 template <typename TurnInfo>
0126 static inline void uu_else_ii(bool condition, TurnInfo& ti)
0127 {
0128 both(ti, condition ? operation_union : operation_intersection);
0129 }
0130
0131 template <typename TurnInfo, typename IntersectionInfo>
0132 static inline void assign_point(TurnInfo& ti,
0133 method_type method,
0134 IntersectionInfo const& info, unsigned int index)
0135 {
0136 ti.method = method;
0137
0138 BOOST_GEOMETRY_ASSERT(index < info.count);
0139
0140 geometry::convert(info.intersections[index], ti.point);
0141 ti.operations[0].fraction = info.fractions[index].robust_ra;
0142 ti.operations[1].fraction = info.fractions[index].robust_rb;
0143 }
0144
0145 template <typename TurnInfo, typename IntersectionInfo, typename DirInfo>
0146 static inline void assign_point_and_correct(TurnInfo& ti,
0147 method_type method,
0148 IntersectionInfo const& info, DirInfo const& dir_info)
0149 {
0150 ti.method = method;
0151
0152
0153
0154 static int const index = 0;
0155
0156 geometry::convert(info.intersections[index], ti.point);
0157
0158 for (int i = 0; i < 2; i++)
0159 {
0160 if (dir_info.arrival[i] == 1)
0161 {
0162
0163
0164 ti.operations[i].fraction = {1, 1};
0165 }
0166 else if (dir_info.arrival[i] == -1)
0167 {
0168
0169 ti.operations[i].fraction = {0, 1};
0170 }
0171 else
0172 {
0173 ti.operations[i].fraction = i == 0 ? info.fractions[index].robust_ra
0174 : info.fractions[index].robust_rb;
0175 }
0176 }
0177 }
0178
0179 template <typename IntersectionInfo>
0180 static inline unsigned int non_opposite_to_index(IntersectionInfo const& info)
0181 {
0182 return info.fractions[0].robust_rb < info.fractions[1].robust_rb
0183 ? 1 : 0;
0184 }
0185
0186 };
0187
0188 template<typename VerifyPolicy>
0189 struct turn_info_verification_functions
0190 {
0191 template <typename Point1, typename Point2>
0192 static inline
0193 typename select_coordinate_type<Point1, Point2>::type
0194 distance_measure(Point1 const& a, Point2 const& b)
0195 {
0196
0197
0198 using coor_t = typename select_coordinate_type<Point1, Point2>::type;
0199
0200 coor_t const dx = get<0>(a) - get<0>(b);
0201 coor_t const dy = get<1>(a) - get<1>(b);
0202 return dx * dx + dy * dy;
0203 }
0204
0205 template
0206 <
0207 std::size_t IndexP,
0208 std::size_t IndexQ,
0209 typename UniqueSubRange1,
0210 typename UniqueSubRange2,
0211 typename UmbrellaStrategy,
0212 typename TurnInfo
0213 >
0214 static inline void set_both_verified(
0215 UniqueSubRange1 const& range_p,
0216 UniqueSubRange2 const& range_q,
0217 UmbrellaStrategy const& umbrella_strategy,
0218 std::size_t index_p, std::size_t index_q,
0219 TurnInfo& ti)
0220 {
0221 BOOST_GEOMETRY_ASSERT(IndexP + IndexQ == 1);
0222 BOOST_GEOMETRY_ASSERT(index_p > 0 && index_p <= 2);
0223 BOOST_GEOMETRY_ASSERT(index_q > 0 && index_q <= 2);
0224
0225 using distance_measure_result_type = typename geometry::coordinate_type<decltype(ti.point)>::type;
0226
0227 bool const p_in_range = index_p < range_p.size();
0228 bool const q_in_range = index_q < range_q.size();
0229 ti.operations[IndexP].remaining_distance
0230 = p_in_range
0231 ? distance_measure(ti.point, range_p.at(index_p))
0232 : distance_measure_result_type{0};
0233 ti.operations[IndexQ].remaining_distance
0234 = q_in_range
0235 ? distance_measure(ti.point, range_q.at(index_q))
0236 : distance_measure_result_type{0};
0237
0238 if (p_in_range && q_in_range)
0239 {
0240
0241
0242
0243 bool const p_closer
0244 = ti.operations[IndexP].remaining_distance
0245 < ti.operations[IndexQ].remaining_distance;
0246 auto const dm
0247 = p_closer
0248 ? get_distance_measure(range_q.at(index_q - 1),
0249 range_q.at(index_q), range_p.at(index_p),
0250 umbrella_strategy)
0251 : get_distance_measure(range_p.at(index_p - 1),
0252 range_p.at(index_p), range_q.at(index_q),
0253 umbrella_strategy);
0254
0255 if (! dm.is_zero())
0256 {
0257
0258
0259 bool const p_left
0260 = p_closer ? dm.is_positive() : dm.is_negative();
0261
0262 ti.operations[IndexP].operation = p_left
0263 ? operation_union : operation_intersection;
0264 ti.operations[IndexQ].operation = p_left
0265 ? operation_intersection : operation_union;
0266 return;
0267 }
0268 }
0269
0270 base_turn_handler::both(ti, operation_continue);
0271 }
0272
0273 template
0274 <
0275 std::size_t IndexP,
0276 std::size_t IndexQ,
0277 typename UniqueSubRange1,
0278 typename UniqueSubRange2,
0279 typename UmbrellaStrategy,
0280 typename TurnInfo
0281 >
0282 static inline void both_collinear(
0283 UniqueSubRange1 const& range_p,
0284 UniqueSubRange2 const& range_q,
0285 UmbrellaStrategy const& umbrella_strategy,
0286 std::size_t index_p, std::size_t index_q,
0287 TurnInfo& ti)
0288 {
0289 if (BOOST_GEOMETRY_CONDITION(VerifyPolicy::use_side_verification))
0290 {
0291 set_both_verified<IndexP, IndexQ>(range_p, range_q, umbrella_strategy,
0292 index_p, index_q, ti);
0293 }
0294 else
0295 {
0296 base_turn_handler::both(ti, operation_continue);
0297 }
0298 }
0299
0300 template
0301 <
0302 typename UniqueSubRange1,
0303 typename UniqueSubRange2,
0304 typename UmbrellaStrategy
0305 >
0306 static inline int verified_side(int side,
0307 UniqueSubRange1 const& range_p,
0308 UniqueSubRange2 const& range_q,
0309 UmbrellaStrategy const& umbrella_strategy,
0310 int index_p, int index_q)
0311 {
0312 if (side == 0
0313 && BOOST_GEOMETRY_CONDITION(VerifyPolicy::use_side_verification))
0314 {
0315 if (index_p >= 1 && range_p.is_last_segment())
0316 {
0317 return 0;
0318 }
0319 if (index_q >= 2 && range_q.is_last_segment())
0320 {
0321 return 0;
0322 }
0323
0324 auto const dm = get_distance_measure(range_p.at(index_p),
0325 range_p.at(index_p + 1),
0326 range_q.at(index_q),
0327 umbrella_strategy);
0328 static decltype(dm.measure) const zero = 0;
0329 return dm.measure == zero ? 0 : dm.measure > zero ? 1 : -1;
0330 }
0331 else
0332 {
0333 return side;
0334 }
0335 }
0336
0337 };
0338
0339
0340 template
0341 <
0342 typename TurnInfo,
0343 typename VerifyPolicy
0344 >
0345 struct touch_interior : public base_turn_handler
0346 {
0347 using fun = turn_info_verification_functions<VerifyPolicy>;
0348
0349 template
0350 <
0351 typename IntersectionInfo,
0352 typename UniqueSubRange
0353 >
0354 static bool handle_as_touch(IntersectionInfo const& info,
0355 UniqueSubRange const& non_touching_range)
0356 {
0357 if (! BOOST_GEOMETRY_CONDITION(VerifyPolicy::use_handle_as_touch))
0358 {
0359 return false;
0360 }
0361
0362
0363
0364
0365
0366
0367
0368
0369
0370
0371
0372
0373
0374
0375
0376
0377
0378
0379
0380
0381
0382
0383
0384
0385
0386
0387
0388
0389
0390
0391
0392 auto const dm = fun::distance_measure(info.intersections[0], non_touching_range.at(1));
0393 decltype(dm) const zero = 0;
0394 bool const result = math::equals(dm, zero);
0395 return result;
0396 }
0397
0398
0399 template
0400 <
0401 unsigned int Index,
0402 typename UniqueSubRange1,
0403 typename UniqueSubRange2,
0404 typename IntersectionInfo,
0405 typename DirInfo,
0406 typename SidePolicy,
0407 typename UmbrellaStrategy
0408 >
0409 static inline void apply(UniqueSubRange1 const& range_p,
0410 UniqueSubRange2 const& range_q,
0411 TurnInfo& ti,
0412 IntersectionInfo const& intersection_info,
0413 DirInfo const& dir_info,
0414 SidePolicy const& side,
0415 UmbrellaStrategy const& umbrella_strategy)
0416 {
0417 assign_point_and_correct(ti, method_touch_interior, intersection_info, dir_info);
0418
0419
0420
0421
0422
0423
0424
0425 BOOST_STATIC_ASSERT(Index <= 1);
0426 static unsigned int const index_p = Index;
0427 static unsigned int const index_q = 1 - Index;
0428
0429 bool const has_pk = ! range_p.is_last_segment();
0430 bool const has_qk = ! range_q.is_last_segment();
0431 int const side_qi_p = dir_info.sides.template get<index_q, 0>();
0432 int const side_qk_p = has_qk ? side.qk_wrt_p1() : 0;
0433
0434 if (side_qi_p == -side_qk_p)
0435 {
0436
0437
0438
0439 unsigned int index = side_qk_p == -1 ? index_p : index_q;
0440 ti.operations[index].operation = operation_union;
0441 ti.operations[1 - index].operation = operation_intersection;
0442 return;
0443 }
0444
0445 int const side_qk_q = has_qk ? side.qk_wrt_q1() : 0;
0446
0447
0448 int const side_pj_q2 = has_qk ? side.pj_wrt_q2() : 0;
0449
0450 if (side_qi_p == -1 && side_qk_p == -1 && side_qk_q == 1)
0451 {
0452
0453
0454 both(ti, operation_intersection);
0455 ti.touch_only = true;
0456 }
0457 else if (side_qi_p == 1 && side_qk_p == 1 && side_qk_q == -1)
0458 {
0459 if (has_qk && side_pj_q2 == -1)
0460 {
0461
0462
0463
0464 both(ti, operation_union);
0465 }
0466 else
0467 {
0468
0469
0470
0471 ti.operations[index_p].operation = operation_union;
0472 ti.operations[index_q].operation = operation_blocked;
0473 }
0474 ti.touch_only = true;
0475 }
0476 else if (side_qi_p == side_qk_p && side_qi_p == side_qk_q)
0477 {
0478
0479
0480
0481
0482 unsigned int index = side_qk_q == 1 ? index_q : index_p;
0483 if (has_qk && side_pj_q2 == 0)
0484 {
0485
0486
0487 index = 1 - index;
0488 }
0489
0490 if (has_pk && has_qk && opposite(side_pj_q2, side_qi_p))
0491 {
0492
0493 int const side_qj_p1 = side.qj_wrt_p1();
0494 int const side_qj_p2 = side.qj_wrt_p2();
0495
0496 if (same(side_qj_p1, side_qj_p2))
0497 {
0498 int const side_pj_q1 = side.pj_wrt_q1();
0499 if (opposite(side_pj_q1, side_pj_q2))
0500 {
0501 index = 1 - index;
0502 }
0503 }
0504 }
0505
0506 ti.operations[index].operation = operation_union;
0507 ti.operations[1 - index].operation = operation_intersection;
0508 ti.touch_only = true;
0509 }
0510 else if (side_qk_p == 0)
0511 {
0512
0513 if (side_qk_q == side_qi_p)
0514 {
0515 fun::template both_collinear<index_p, index_q>(range_p, range_q, umbrella_strategy,
0516 1, 2, ti);
0517 }
0518 else
0519 {
0520
0521
0522
0523 ti.operations[index_p].operation = side_qk_q == 1
0524 ? operation_intersection
0525 : operation_union;
0526 ti.operations[index_q].operation = operation_blocked;
0527 }
0528 }
0529 else
0530 {
0531
0532 ti.method = method_error;
0533 }
0534 }
0535 };
0536
0537
0538 template
0539 <
0540 typename TurnInfo,
0541 typename VerifyPolicy
0542 >
0543 struct touch : public base_turn_handler
0544 {
0545 using fun = turn_info_verification_functions<VerifyPolicy>;
0546
0547 static inline bool between(int side1, int side2, int turn)
0548 {
0549 return side1 == side2 && ! opposite(side1, turn);
0550 }
0551
0552 template
0553 <
0554 typename UniqueSubRange1,
0555 typename UniqueSubRange2,
0556 typename UmbrellaStrategy
0557 >
0558 static inline bool handle_imperfect_touch(UniqueSubRange1 const& range_p,
0559 UniqueSubRange2 const& range_q,
0560 int side_pk_q2,
0561 UmbrellaStrategy const& umbrella_strategy,
0562 TurnInfo& ti)
0563 {
0564 if (! BOOST_GEOMETRY_CONDITION(VerifyPolicy::use_handle_imperfect_touch))
0565 {
0566 return false;
0567 }
0568
0569
0570
0571
0572
0573
0574
0575
0576
0577
0578
0579
0580
0581
0582
0583
0584
0585
0586
0587
0588
0589
0590
0591
0592 auto has_distance = [&](auto const& r1, auto const& r2) -> bool
0593 {
0594 auto const d1 = get_distance_measure(r1.at(0), r1.at(1), r2.at(1), umbrella_strategy);
0595 auto const d2 = get_distance_measure(r2.at(1), r2.at(2), r1.at(0), umbrella_strategy);
0596 return d1.measure > 0 && d2.measure > 0;
0597 };
0598
0599 if (side_pk_q2 == -1 && has_distance(range_p, range_q))
0600 {
0601
0602
0603
0604
0605 ti.operations[0].operation = operation_blocked;
0606
0607
0608 ti.operations[1].operation = operation_union;
0609 ti.touch_only = true;
0610 return true;
0611 }
0612
0613 if (side_pk_q2 == 1 && has_distance(range_q, range_p))
0614 {
0615
0616
0617 ti.operations[0].operation = operation_union;
0618 ti.operations[1].operation = operation_blocked;
0619 ti.touch_only = true;
0620 return true;
0621 }
0622 return false;
0623 }
0624
0625 template
0626 <
0627 typename UniqueSubRange1,
0628 typename UniqueSubRange2,
0629 typename IntersectionInfo,
0630 typename DirInfo,
0631 typename SideCalculator,
0632 typename UmbrellaStrategy
0633 >
0634 static inline void apply(UniqueSubRange1 const& range_p,
0635 UniqueSubRange2 const& range_q,
0636 TurnInfo& ti,
0637 IntersectionInfo const& intersection_info,
0638 DirInfo const& dir_info,
0639 SideCalculator const& side,
0640 UmbrellaStrategy const& umbrella_strategy)
0641 {
0642 assign_point_and_correct(ti, method_touch, intersection_info, dir_info);
0643
0644 bool const has_pk = ! range_p.is_last_segment();
0645 bool const has_qk = ! range_q.is_last_segment();
0646
0647 int const side_pk_q1 = has_pk ? side.pk_wrt_q1() : 0;
0648
0649 int const side_qi_p1 = fun::verified_side(dir_info.sides.template get<1, 0>(),
0650 range_p, range_q, umbrella_strategy, 0, 0);
0651 int const side_qk_p1 = has_qk
0652 ? fun::verified_side(side.qk_wrt_p1(), range_p, range_q,
0653 umbrella_strategy, 0, 2)
0654 : 0;
0655
0656
0657
0658 if (! opposite(side_qi_p1, side_qk_p1))
0659 {
0660 int const side_pk_q2 = has_pk && has_qk ? side.pk_wrt_q2() : 0;
0661 int const side_pk_p = has_pk ? side.pk_wrt_p1() : 0;
0662 int const side_qk_q = has_qk ? side.qk_wrt_q1() : 0;
0663
0664 bool const q_turns_left = side_qk_q == 1;
0665
0666 bool const block_q = side_qk_p1 == 0
0667 && ! same(side_qi_p1, side_qk_q)
0668 ;
0669
0670
0671
0672
0673 if (side_pk_p == side_qi_p1
0674 || side_pk_p == side_qk_p1
0675 || (side_qi_p1 == 0 && side_qk_p1 == 0 && side_pk_p != -1))
0676 {
0677 if (side_qk_p1 == 0 && side_pk_q1 == 0
0678 && has_pk && has_qk
0679 && handle_imperfect_touch(range_p, range_q, side_pk_q2, umbrella_strategy, ti))
0680 {
0681
0682
0683 return;
0684 }
0685
0686
0687 if (side_pk_q2 == 0 && ! block_q)
0688 {
0689 fun::template both_collinear<0, 1>(range_p, range_q, umbrella_strategy,
0690 2, 2, ti);
0691 return;
0692 }
0693
0694
0695
0696 if (side_pk_q1 == 0)
0697 {
0698 ti.operations[0].operation = operation_blocked;
0699
0700
0701 ti.operations[1].operation = block_q ? operation_blocked
0702 : q_turns_left ? operation_intersection
0703 : operation_union;
0704 return;
0705 }
0706
0707
0708
0709 if (between(side_pk_q1, side_pk_q2, side_qk_q))
0710 {
0711 ui_else_iu(q_turns_left, ti);
0712 if (block_q)
0713 {
0714 ti.operations[1].operation = operation_blocked;
0715 }
0716 return;
0717 }
0718
0719
0720
0721 if (side_pk_q2 == -side_qk_q)
0722 {
0723 ui_else_iu(! q_turns_left, ti);
0724 ti.touch_only = true;
0725 return;
0726 }
0727
0728
0729
0730 if (side_pk_q1 == -side_qk_q)
0731 {
0732 uu_else_ii(! q_turns_left, ti);
0733 if (block_q)
0734 {
0735 ti.operations[1].operation = operation_blocked;
0736 }
0737 else
0738 {
0739 ti.touch_only = true;
0740 }
0741 return;
0742 }
0743 }
0744 else
0745 {
0746
0747 ti.operations[0].operation = q_turns_left
0748 ? operation_intersection
0749 : operation_union;
0750 ti.operations[1].operation = block_q
0751 ? operation_blocked
0752 : side_qi_p1 == 1 || side_qk_p1 == 1
0753 ? operation_union
0754 : operation_intersection;
0755 if (! block_q)
0756 {
0757 ti.touch_only = true;
0758 }
0759
0760 return;
0761 }
0762 }
0763 else
0764 {
0765
0766
0767 int const side_pk_p = has_pk
0768 ? fun::verified_side(side.pk_wrt_p1(), range_p, range_p,
0769 umbrella_strategy, 0, 2)
0770 : 0;
0771 bool const right_to_left = side_qk_p1 == 1;
0772
0773
0774 if (side_pk_p == side_qi_p1)
0775 {
0776
0777 if (side_pk_q1 == 0)
0778 {
0779 ti.operations[0].operation = operation_blocked;
0780 ti.operations[1].operation = right_to_left
0781 ? operation_union : operation_intersection;
0782 return;
0783 }
0784
0785 if (side_pk_q1 == side_qk_p1)
0786 {
0787 uu_else_ii(right_to_left, ti);
0788 ti.touch_only = true;
0789 return;
0790 }
0791 }
0792
0793
0794 if (side_pk_p == side_qk_p1)
0795 {
0796 int const side_pk_q2 = has_pk ? side.pk_wrt_q2() : 0;
0797
0798
0799 if (side_pk_q2 == 0)
0800 {
0801 both(ti, operation_continue);
0802 return;
0803 }
0804 if (side_pk_q2 == side_qk_p1)
0805 {
0806 ui_else_iu(right_to_left, ti);
0807 ti.touch_only = true;
0808 return;
0809 }
0810 }
0811
0812 ui_else_iu(! right_to_left, ti);
0813 return;
0814 }
0815 }
0816 };
0817
0818
0819 template
0820 <
0821 typename TurnInfo,
0822 typename VerifyPolicy
0823 >
0824 struct equal : public base_turn_handler
0825 {
0826 using fun = turn_info_verification_functions<VerifyPolicy>;
0827
0828 template
0829 <
0830 typename UniqueSubRange1,
0831 typename UniqueSubRange2,
0832 typename IntersectionInfo,
0833 typename DirInfo,
0834 typename SideCalculator,
0835 typename UmbrellaStrategy
0836 >
0837 static inline void apply(UniqueSubRange1 const& range_p,
0838 UniqueSubRange2 const& range_q,
0839 TurnInfo& ti,
0840 IntersectionInfo const& info,
0841 DirInfo const& ,
0842 SideCalculator const& side,
0843 UmbrellaStrategy const& umbrella_strategy)
0844 {
0845
0846 assign_point(ti, method_equal, info, non_opposite_to_index(info));
0847
0848 bool const has_pk = ! range_p.is_last_segment();
0849 bool const has_qk = ! range_q.is_last_segment();
0850
0851 int const side_pk_q2 = has_pk && has_qk ? side.pk_wrt_q2() : 0;
0852 int const side_pk_p = has_pk ? side.pk_wrt_p1() : 0;
0853 int const side_qk_p = has_qk ? side.qk_wrt_p1() : 0;
0854
0855 if (has_pk && has_qk && side_pk_p == side_qk_p)
0856 {
0857
0858
0859 int const side_qk_p2 = side.qk_wrt_p2();
0860
0861 if (opposite(side_qk_p2, side_pk_q2))
0862 {
0863 ui_else_iu(side_pk_q2 == 1, ti);
0864 return;
0865 }
0866 }
0867
0868
0869
0870
0871
0872 if (side_pk_q2 == 0 && side_pk_p == side_qk_p)
0873 {
0874 fun::template both_collinear<0, 1>(range_p, range_q, umbrella_strategy, 2, 2, ti);
0875 return;
0876 }
0877
0878
0879
0880 if (! opposite(side_pk_p, side_qk_p))
0881 {
0882
0883 ui_else_iu(side_pk_q2 != -1, ti);
0884 }
0885 else
0886 {
0887
0888
0889 ui_else_iu(side_pk_p != -1, ti);
0890 }
0891 }
0892 };
0893
0894 template
0895 <
0896 typename TurnInfo,
0897 typename VerifyPolicy
0898 >
0899 struct start : public base_turn_handler
0900 {
0901 template
0902 <
0903 typename UniqueSubRange1,
0904 typename UniqueSubRange2,
0905 typename IntersectionInfo,
0906 typename DirInfo,
0907 typename SideCalculator,
0908 typename UmbrellaStrategy
0909 >
0910 static inline bool apply(UniqueSubRange1 const& ,
0911 UniqueSubRange2 const& ,
0912 TurnInfo& ti,
0913 IntersectionInfo const& info,
0914 DirInfo const& dir_info,
0915 SideCalculator const& side,
0916 UmbrellaStrategy const& )
0917 {
0918 if (! BOOST_GEOMETRY_CONDITION(VerifyPolicy::use_start_turn))
0919 {
0920 return false;
0921 }
0922
0923
0924 BOOST_GEOMETRY_ASSERT(dir_info.how_a != dir_info.how_b);
0925 BOOST_GEOMETRY_ASSERT(dir_info.how_a == -1 || dir_info.how_b == -1);
0926 BOOST_GEOMETRY_ASSERT(dir_info.how_a == 0 || dir_info.how_b == 0);
0927
0928 if (dir_info.how_b == -1)
0929 {
0930
0931
0932
0933
0934
0935
0936 int const side_qj_p1 = side.qj_wrt_p1();
0937 ui_else_iu(side_qj_p1 == -1, ti);
0938 }
0939 else if (dir_info.how_a == -1)
0940 {
0941
0942 int const side_pj_q1 = side.pj_wrt_q1();
0943 ui_else_iu(side_pj_q1 == 1, ti);
0944 }
0945
0946
0947 assign_point_and_correct(ti, method_start, info, dir_info);
0948 return true;
0949 }
0950
0951 };
0952
0953
0954 template
0955 <
0956 typename TurnInfo,
0957 typename AssignPolicy
0958 >
0959 struct equal_opposite : public base_turn_handler
0960 {
0961 template
0962 <
0963 typename UniqueSubRange1,
0964 typename UniqueSubRange2,
0965 typename OutputIterator,
0966 typename IntersectionInfo
0967 >
0968 static inline void apply(
0969 UniqueSubRange1 const& ,
0970 UniqueSubRange2 const& ,
0971 TurnInfo tp,
0972 OutputIterator& out,
0973 IntersectionInfo const& intersection_info)
0974 {
0975
0976 if (BOOST_GEOMETRY_CONDITION(AssignPolicy::include_opposite))
0977 {
0978 tp.method = method_equal;
0979 for (unsigned int i = 0; i < 2; i++)
0980 {
0981 tp.operations[i].operation = operation_opposite;
0982 }
0983 for (unsigned int i = 0; i < intersection_info.i_info().count; i++)
0984 {
0985 assign_point(tp, method_none, intersection_info.i_info(), i);
0986 *out++ = tp;
0987 }
0988 }
0989 }
0990 };
0991
0992 template
0993 <
0994 typename TurnInfo,
0995 typename VerifyPolicy
0996 >
0997 struct collinear : public base_turn_handler
0998 {
0999 using fun = turn_info_verification_functions<VerifyPolicy>;
1000
1001 template
1002 <
1003 typename IntersectionInfo,
1004 typename UniqueSubRange1,
1005 typename UniqueSubRange2,
1006 typename DirInfo
1007 >
1008 static bool handle_as_equal(IntersectionInfo const& info,
1009 UniqueSubRange1 const& range_p,
1010 UniqueSubRange2 const& range_q,
1011 DirInfo const& dir_info)
1012 {
1013 if (! BOOST_GEOMETRY_CONDITION(VerifyPolicy::use_handle_as_equal))
1014 {
1015 return false;
1016 }
1017
1018 int const arrival_p = dir_info.arrival[0];
1019 int const arrival_q = dir_info.arrival[1];
1020 if (arrival_p * arrival_q != -1 || info.count != 2)
1021 {
1022
1023 return false;
1024 }
1025
1026 auto const dm = arrival_p == 1
1027 ? fun::distance_measure(info.intersections[1], range_q.at(1))
1028 : fun::distance_measure(info.intersections[1], range_p.at(1));
1029 decltype(dm) const zero = 0;
1030 return math::equals(dm, zero);
1031 }
1032
1033
1034
1035
1036
1037
1038
1039
1040
1041
1042
1043
1044
1045
1046
1047
1048
1049
1050
1051
1052
1053
1054
1055
1056
1057
1058
1059
1060
1061
1062
1063
1064
1065
1066
1067
1068
1069
1070
1071
1072
1073
1074
1075
1076
1077
1078
1079
1080 template
1081 <
1082 typename UniqueSubRange1,
1083 typename UniqueSubRange2,
1084 typename IntersectionInfo,
1085 typename DirInfo,
1086 typename SidePolicy
1087 >
1088 static inline void apply(
1089 UniqueSubRange1 const& range_p,
1090 UniqueSubRange2 const& range_q,
1091 TurnInfo& ti,
1092 IntersectionInfo const& info,
1093 DirInfo const& dir_info,
1094 SidePolicy const& side)
1095 {
1096
1097 assign_point(ti, method_collinear, info, non_opposite_to_index(info));
1098
1099 int const arrival_p = dir_info.arrival[0];
1100
1101 BOOST_GEOMETRY_ASSERT(arrival_p != 0);
1102
1103 bool const has_pk = ! range_p.is_last_segment();
1104 bool const has_qk = ! range_q.is_last_segment();
1105 int const side_p = has_pk ? side.pk_wrt_p1() : 0;
1106 int const side_q = has_qk ? side.qk_wrt_q1() : 0;
1107
1108
1109 int const side_p_or_q = arrival_p == 1
1110 ? side_p
1111 : side_q
1112 ;
1113
1114
1115 int const product = arrival_p * side_p_or_q;
1116
1117 if (product == 0)
1118 {
1119 both(ti, operation_continue);
1120 }
1121 else
1122 {
1123 ui_else_iu(product == 1, ti);
1124 }
1125
1126
1127
1128 ti.operations[0].remaining_distance
1129 = side_p == 0 && has_pk
1130 ? fun::distance_measure(ti.point, range_p.at(2))
1131 : fun::distance_measure(ti.point, range_p.at(1));
1132 ti.operations[1].remaining_distance
1133 = side_q == 0 && has_qk
1134 ? fun::distance_measure(ti.point, range_q.at(2))
1135 : fun::distance_measure(ti.point, range_q.at(1));
1136 }
1137 };
1138
1139 template
1140 <
1141 typename TurnInfo,
1142 typename AssignPolicy
1143 >
1144 struct collinear_opposite : public base_turn_handler
1145 {
1146 private :
1147
1148
1149
1150
1151
1152
1153
1154
1155
1156
1157
1158
1159
1160
1161
1162
1163
1164
1165
1166
1167
1168
1169
1170
1171 template <unsigned int Index, typename IntersectionInfo>
1172 static inline bool set_tp(int side_rk_r, TurnInfo& tp,
1173 IntersectionInfo const& intersection_info)
1174 {
1175 BOOST_STATIC_ASSERT(Index <= 1);
1176
1177 operation_type blocked = operation_blocked;
1178 switch(side_rk_r)
1179 {
1180 case 1 :
1181
1182 tp.operations[Index].operation = operation_intersection;
1183 break;
1184 case -1 :
1185
1186 tp.operations[Index].operation = operation_union;
1187 break;
1188 case 0 :
1189
1190
1191
1192
1193
1194 if (BOOST_GEOMETRY_CONDITION(AssignPolicy::include_opposite))
1195 {
1196 tp.operations[Index].operation = operation_opposite;
1197 blocked = operation_opposite;
1198 }
1199 else
1200 {
1201 return false;
1202 }
1203 break;
1204 }
1205
1206
1207 tp.operations[1 - Index].operation = blocked;
1208
1209
1210
1211
1212 assign_point(tp, method_collinear, intersection_info, 1 - Index);
1213 return true;
1214 }
1215
1216 public:
1217 static inline void empty_transformer(TurnInfo &) {}
1218
1219 template
1220 <
1221 typename UniqueSubRange1,
1222 typename UniqueSubRange2,
1223 typename OutputIterator,
1224 typename IntersectionInfo,
1225 typename SidePolicy
1226 >
1227 static inline void apply(
1228 UniqueSubRange1 const& range_p,
1229 UniqueSubRange2 const& range_q,
1230
1231
1232 TurnInfo const& tp_model,
1233 OutputIterator& out,
1234
1235 IntersectionInfo const& intersection_info,
1236 SidePolicy const& side)
1237 {
1238 apply(range_p, range_q,
1239 tp_model, out, intersection_info, side, empty_transformer);
1240 }
1241
1242 template
1243 <
1244 typename UniqueSubRange1,
1245 typename UniqueSubRange2,
1246 typename OutputIterator,
1247 typename IntersectionInfo,
1248 typename SidePolicy,
1249 typename TurnTransformer
1250 >
1251 static inline void apply(
1252 UniqueSubRange1 const& range_p,
1253 UniqueSubRange2 const& range_q,
1254
1255
1256 TurnInfo const& tp_model,
1257 OutputIterator& out,
1258
1259 IntersectionInfo const& info,
1260 SidePolicy const& side,
1261 TurnTransformer turn_transformer)
1262 {
1263 TurnInfo tp = tp_model;
1264
1265 int const arrival_p = info.d_info().arrival[0];
1266 int const arrival_q = info.d_info().arrival[1];
1267
1268
1269 if ( arrival_p == 1
1270 && ! range_p.is_last_segment()
1271 && set_tp<0>(side.pk_wrt_p1(), tp, info.i_info()) )
1272 {
1273 turn_transformer(tp);
1274
1275 *out++ = tp;
1276 }
1277
1278
1279 if ( arrival_q == 1
1280 && ! range_q.is_last_segment()
1281 && set_tp<1>(side.qk_wrt_q1(), tp, info.i_info()) )
1282 {
1283 turn_transformer(tp);
1284
1285 *out++ = tp;
1286 }
1287
1288 if (BOOST_GEOMETRY_CONDITION(AssignPolicy::include_opposite))
1289 {
1290
1291 if ((arrival_q == -1 && arrival_p == 0)
1292 || (arrival_p == -1 && arrival_q == 0))
1293 {
1294 for (unsigned int i = 0; i < 2; i++)
1295 {
1296 tp.operations[i].operation = operation_opposite;
1297 }
1298 for (unsigned int i = 0; i < info.i_info().count; i++)
1299 {
1300 assign_point(tp, method_collinear, info.i_info(), i);
1301 *out++ = tp;
1302 }
1303 }
1304 }
1305
1306 }
1307 };
1308
1309
1310 template
1311 <
1312 typename TurnInfo
1313 >
1314 struct crosses : public base_turn_handler
1315 {
1316 template <typename IntersectionInfo, typename DirInfo>
1317 static inline void apply(TurnInfo& ti,
1318 IntersectionInfo const& intersection_info,
1319 DirInfo const& dir_info)
1320 {
1321 assign_point(ti, method_crosses, intersection_info, 0);
1322
1323
1324
1325
1326
1327
1328 int const side_qi_p1 = dir_info.sides.template get<1, 0>();
1329 unsigned int const index = side_qi_p1 == 1 ? 0 : 1;
1330 ti.operations[index].operation = operation_union;
1331 ti.operations[1 - index].operation = operation_intersection;
1332 }
1333 };
1334
1335 struct only_convert : public base_turn_handler
1336 {
1337 template<typename TurnInfo, typename IntersectionInfo>
1338 static inline void apply(TurnInfo& ti, IntersectionInfo const& intersection_info)
1339 {
1340 assign_point(ti, method_none, intersection_info, 0);
1341 ti.operations[0].operation = operation_continue;
1342 ti.operations[1].operation = operation_continue;
1343 }
1344 };
1345
1346
1347
1348
1349
1350
1351 struct assign_null_policy
1352 {
1353 static bool const include_no_turn = false;
1354 static bool const include_degenerate = false;
1355 static bool const include_opposite = false;
1356 static bool const include_start_turn = false;
1357 };
1358
1359 struct assign_policy_only_start_turns
1360 {
1361 static bool const include_no_turn = false;
1362 static bool const include_degenerate = false;
1363 static bool const include_opposite = false;
1364 static bool const include_start_turn = true;
1365 };
1366
1367
1368
1369
1370
1371
1372
1373
1374
1375
1376
1377
1378 template<typename AssignPolicy>
1379 struct get_turn_info
1380 {
1381
1382
1383
1384 template
1385 <
1386 typename UniqueSubRange1,
1387 typename UniqueSubRange2,
1388 typename TurnInfo,
1389 typename UmbrellaStrategy,
1390 typename RobustPolicy,
1391 typename OutputIterator
1392 >
1393 static inline OutputIterator apply(
1394 UniqueSubRange1 const& range_p,
1395 UniqueSubRange2 const& range_q,
1396 TurnInfo const& tp_model,
1397 UmbrellaStrategy const& umbrella_strategy,
1398 RobustPolicy const& robust_policy,
1399 OutputIterator out)
1400 {
1401 typedef intersection_info
1402 <
1403 UniqueSubRange1, UniqueSubRange2,
1404 typename TurnInfo::point_type,
1405 UmbrellaStrategy,
1406 RobustPolicy
1407 > inters_info;
1408
1409 inters_info inters(range_p, range_q, umbrella_strategy, robust_policy);
1410
1411 char const method = inters.d_info().how;
1412
1413 if (method == 'd')
1414 {
1415
1416 return out;
1417 }
1418
1419
1420 TurnInfo tp = tp_model;
1421
1422 bool const handle_as_touch_interior = method == 'm';
1423 bool const handle_as_cross = method == 'i';
1424 bool handle_as_touch = method == 't';
1425 bool handle_as_equal = method == 'e';
1426 bool const handle_as_collinear = method == 'c';
1427 bool const handle_as_degenerate = method == '0';
1428 bool const handle_as_start = method == 's';
1429
1430
1431 bool do_only_convert = method == 'a' || method == 'f';
1432
1433 if (handle_as_start)
1434 {
1435
1436 using handler = start<TurnInfo, verify_policy_aa>;
1437 if (BOOST_GEOMETRY_CONDITION(AssignPolicy::include_start_turn)
1438 && handler::apply(range_p, range_q, tp,
1439 inters.i_info(), inters.d_info(), inters.sides(),
1440 umbrella_strategy))
1441 {
1442 *out++ = tp;
1443 }
1444 else
1445 {
1446 do_only_convert = true;
1447 }
1448 }
1449
1450 if (handle_as_touch_interior)
1451 {
1452 using handler = touch_interior<TurnInfo, verify_policy_aa>;
1453
1454 if ( inters.d_info().arrival[1] == 1 )
1455 {
1456
1457 if (handler::handle_as_touch(inters.i_info(), range_p))
1458 {
1459 handle_as_touch = true;
1460 }
1461 else
1462 {
1463 handler::template apply<0>(range_p, range_q, tp, inters.i_info(), inters.d_info(),
1464 inters.sides(), umbrella_strategy);
1465 *out++ = tp;
1466 }
1467 }
1468 else
1469 {
1470
1471 if (handler::handle_as_touch(inters.i_info(), range_q))
1472 {
1473 handle_as_touch = true;
1474 }
1475 else
1476 {
1477 handler::template apply<1>(range_q, range_p, tp, inters.i_info(), inters.d_info(),
1478 inters.swapped_sides(), umbrella_strategy);
1479 *out++ = tp;
1480 }
1481 }
1482 }
1483
1484 if (handle_as_cross)
1485 {
1486 crosses<TurnInfo>::apply(tp, inters.i_info(), inters.d_info());
1487 *out++ = tp;
1488 }
1489
1490 if (handle_as_touch)
1491 {
1492
1493 using handler = touch<TurnInfo, verify_policy_aa>;
1494 handler::apply(range_p, range_q, tp, inters.i_info(), inters.d_info(), inters.sides(),
1495 umbrella_strategy);
1496 *out++ = tp;
1497 }
1498
1499 if (handle_as_collinear)
1500 {
1501
1502 if ( ! inters.d_info().opposite )
1503 {
1504 using handler = collinear<TurnInfo, verify_policy_aa>;
1505 if (inters.d_info().arrival[0] == 0
1506 || handler::handle_as_equal(inters.i_info(), range_p, range_q, inters.d_info()))
1507 {
1508
1509 handle_as_equal = true;
1510 }
1511 else
1512 {
1513 handler::apply(range_p, range_q, tp, inters.i_info(),
1514 inters.d_info(), inters.sides());
1515 *out++ = tp;
1516 }
1517 }
1518 else
1519 {
1520 collinear_opposite
1521 <
1522 TurnInfo,
1523 AssignPolicy
1524 >::apply(range_p, range_q, tp, out, inters, inters.sides());
1525
1526 }
1527 }
1528
1529 if (handle_as_equal)
1530 {
1531 if ( ! inters.d_info().opposite )
1532 {
1533
1534
1535 using handler = equal<TurnInfo, verify_policy_aa>;
1536 handler::apply(range_p, range_q, tp,
1537 inters.i_info(), inters.d_info(), inters.sides(),
1538 umbrella_strategy);
1539 if (handle_as_collinear)
1540 {
1541
1542
1543 tp.method = method_collinear;
1544 }
1545 *out++ = tp;
1546 }
1547 else
1548 {
1549 equal_opposite
1550 <
1551 TurnInfo,
1552 AssignPolicy
1553 >::apply(range_p, range_q, tp, out, inters);
1554
1555 }
1556 }
1557
1558 if ((handle_as_degenerate
1559 && BOOST_GEOMETRY_CONDITION(AssignPolicy::include_degenerate))
1560 || (do_only_convert
1561 && BOOST_GEOMETRY_CONDITION(AssignPolicy::include_no_turn)))
1562 {
1563 if (inters.i_info().count > 0)
1564 {
1565 only_convert::apply(tp, inters.i_info());
1566 *out++ = tp;
1567 }
1568 }
1569
1570 return out;
1571 }
1572 };
1573
1574
1575 }}
1576 #endif
1577
1578
1579 }}
1580
1581
1582 #endif