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