File indexing completed on 2025-09-17 08:30:39
0001
0002
0003
0004
0005
0006
0007
0008
0009
0010
0011
0012
0013
0014
0015 #ifndef BOOST_GEOMETRY_ALGORITHMS_DETAIL_OVERLAY_TRAVERSAL_HPP
0016 #define BOOST_GEOMETRY_ALGORITHMS_DETAIL_OVERLAY_TRAVERSAL_HPP
0017
0018 #include <cstddef>
0019 #include <set>
0020
0021 #include <boost/range/begin.hpp>
0022 #include <boost/range/end.hpp>
0023 #include <boost/range/value_type.hpp>
0024
0025 #include <boost/geometry/algorithms/detail/overlay/cluster_info.hpp>
0026 #include <boost/geometry/algorithms/detail/overlay/debug_traverse.hpp>
0027 #include <boost/geometry/algorithms/detail/overlay/is_self_turn.hpp>
0028 #include <boost/geometry/algorithms/detail/overlay/sort_by_side.hpp>
0029 #include <boost/geometry/algorithms/detail/overlay/turn_info.hpp>
0030 #include <boost/geometry/core/assert.hpp>
0031 #include <boost/geometry/util/constexpr.hpp>
0032
0033 #if defined(BOOST_GEOMETRY_DEBUG_INTERSECTION) \
0034 || defined(BOOST_GEOMETRY_OVERLAY_REPORT_WKT) \
0035 || defined(BOOST_GEOMETRY_DEBUG_TRAVERSE)
0036 # include <string>
0037 # include <boost/geometry/algorithms/detail/overlay/debug_turn_info.hpp>
0038 # include <boost/geometry/io/wkt/wkt.hpp>
0039 #endif
0040
0041 namespace boost { namespace geometry
0042 {
0043
0044 #ifndef DOXYGEN_NO_DETAIL
0045 namespace detail { namespace overlay
0046 {
0047
0048 template
0049 <
0050 bool Reverse1,
0051 bool Reverse2,
0052 overlay_type OverlayType,
0053 typename Geometry1,
0054 typename Geometry2,
0055 typename Turns,
0056 typename Clusters,
0057 typename Strategy,
0058 typename Visitor
0059 >
0060 struct traversal
0061 {
0062 private :
0063
0064 static const operation_type target_operation = operation_from_overlay<OverlayType>::value;
0065
0066 using side_compare_type = typename sort_by_side::side_compare<target_operation>::type;
0067 using turn_type = typename boost::range_value<Turns>::type;
0068 using turn_operation_type = typename turn_type::turn_operation_type;
0069
0070 using point_type = geometry::point_type_t<Geometry1>;
0071 using sbs_type = sort_by_side::side_sorter
0072 <
0073 Reverse1, Reverse2, OverlayType,
0074 point_type, Strategy, side_compare_type
0075 >;
0076
0077 public :
0078 inline traversal(Geometry1 const& geometry1, Geometry2 const& geometry2,
0079 Turns& turns, Clusters const& clusters,
0080 Strategy const& strategy,
0081 Visitor& visitor)
0082 : m_geometry1(geometry1)
0083 , m_geometry2(geometry2)
0084 , m_turns(turns)
0085 , m_clusters(clusters)
0086 , m_strategy(strategy)
0087 , m_visitor(visitor)
0088 {
0089 }
0090
0091 template <typename TurnInfoMap>
0092 inline void finalize_visit_info(TurnInfoMap& turn_info_map)
0093 {
0094 for (auto& turn : m_turns)
0095 {
0096 for (int i = 0; i < 2; i++)
0097 {
0098 turn_operation_type& op = turn.operations[i];
0099 if (op.visited.visited()
0100 || op.visited.started()
0101 || op.visited.finished() )
0102 {
0103 ring_identifier const ring_id = ring_id_by_seg_id(op.seg_id);
0104 turn_info_map[ring_id].has_traversed_turn = true;
0105
0106 if (op.operation == operation_continue)
0107 {
0108
0109
0110 turn_operation_type& other_op = turn.operations[1 - i];
0111 ring_identifier const other_ring_id
0112 = ring_id_by_seg_id(other_op.seg_id);
0113 turn_info_map[other_ring_id].has_traversed_turn = true;
0114 }
0115 }
0116 op.visited.finalize();
0117 }
0118 }
0119 }
0120
0121
0122 inline void set_visited_in_cluster(signed_size_type cluster_id,
0123 signed_size_type rank)
0124 {
0125 auto mit = m_clusters.find(cluster_id);
0126 BOOST_ASSERT(mit != m_clusters.end());
0127
0128 cluster_info const& cinfo = mit->second;
0129
0130 for (auto turn_index : cinfo.turn_indices)
0131 {
0132 turn_type& turn = m_turns[turn_index];
0133
0134 for (auto& op : turn.operations)
0135 {
0136 if (op.visited.none() && op.enriched.rank == rank)
0137 {
0138 op.visited.set_visited();
0139 }
0140 }
0141 }
0142 }
0143 inline void set_visited(turn_type& turn, turn_operation_type& op)
0144 {
0145 if (op.operation == detail::overlay::operation_continue)
0146 {
0147
0148 for (int i = 0; i < 2; i++)
0149 {
0150 turn_operation_type& turn_op = turn.operations[i];
0151 if (turn_op.visited.none())
0152 {
0153 turn_op.visited.set_visited();
0154 }
0155 }
0156 }
0157 else
0158 {
0159 op.visited.set_visited();
0160 }
0161 if (turn.is_clustered())
0162 {
0163 set_visited_in_cluster(turn.cluster_id, op.enriched.rank);
0164 }
0165 }
0166
0167 inline bool is_visited(turn_type const& , turn_operation_type const& op,
0168 signed_size_type , int) const
0169 {
0170 return op.visited.visited();
0171 }
0172
0173 template <signed_size_type segment_identifier::*Member>
0174 inline bool select_source_generic(turn_type const& turn,
0175 segment_identifier const& current,
0176 segment_identifier const& previous) const
0177 {
0178 turn_operation_type const& op0 = turn.operations[0];
0179 turn_operation_type const& op1 = turn.operations[1];
0180
0181 bool const switch_source = op0.enriched.region_id != -1
0182 && op0.enriched.region_id == op1.enriched.region_id;
0183
0184 #if defined(BOOST_GEOMETRY_DEBUG_TRAVERSAL_SWITCH_DETECTOR)
0185 if (switch_source)
0186 {
0187 std::cout << "Switch source at " << &turn << std::endl;
0188 }
0189 else
0190 {
0191 std::cout << "DON'T SWITCH SOURCES at " << &turn << std::endl;
0192 }
0193 #endif
0194 return switch_source
0195 ? current.*Member != previous.*Member
0196 : current.*Member == previous.*Member;
0197 }
0198
0199 inline bool select_source(turn_type const& turn,
0200 segment_identifier const& candidate_seg_id,
0201 segment_identifier const& previous_seg_id) const
0202 {
0203
0204
0205 return OverlayType == overlay_buffer || is_self_turn<OverlayType>(turn)
0206 ? select_source_generic<&segment_identifier::multi_index>(
0207 turn, candidate_seg_id, previous_seg_id)
0208 : select_source_generic<&segment_identifier::source_index>(
0209 turn, candidate_seg_id, previous_seg_id);
0210 }
0211
0212 inline bool traverse_possible(signed_size_type turn_index) const
0213 {
0214 if (turn_index == -1)
0215 {
0216 return false;
0217 }
0218
0219 turn_type const& turn = m_turns[turn_index];
0220
0221
0222
0223 return turn.is_clustered()
0224 || turn.has(target_operation)
0225 || turn.has(operation_continue);
0226 }
0227
0228 inline std::size_t get_shortcut_level(turn_operation_type const& op,
0229 signed_size_type start_turn_index,
0230 signed_size_type origin_turn_index,
0231 std::size_t level = 1) const
0232 {
0233 signed_size_type next_turn_index = op.enriched.get_next_turn_index();
0234 if (next_turn_index == -1)
0235 {
0236 return 0;
0237 }
0238 if (next_turn_index == start_turn_index)
0239 {
0240
0241 return 0;
0242 }
0243 if (next_turn_index == origin_turn_index)
0244 {
0245
0246 return level;
0247 }
0248 if (level > 10)
0249 {
0250
0251 return 0;
0252 }
0253
0254 turn_type const& next_turn = m_turns[next_turn_index];
0255 for (int i = 0; i < 2; i++)
0256 {
0257 turn_operation_type const& next_op = next_turn.operations[i];
0258 if (next_op.operation == target_operation
0259 && ! next_op.visited.finished()
0260 && ! next_op.visited.visited())
0261 {
0262
0263 if (get_shortcut_level(next_op, start_turn_index,
0264 origin_turn_index, level + 1))
0265 {
0266 return level + 1;
0267 }
0268 }
0269 }
0270 return 0;
0271 }
0272
0273 inline
0274 bool select_cc_operation(turn_type const& turn,
0275 signed_size_type start_turn_index,
0276 int& selected_op_index) const
0277 {
0278
0279
0280
0281
0282
0283 signed_size_type next[2] = {0};
0284 bool possible[2] = {0};
0285 bool close[2] = {0};
0286
0287 for (int i = 0; i < 2; i++)
0288 {
0289 next[i] = turn.operations[i].enriched.get_next_turn_index();
0290 possible[i] = traverse_possible(next[i]);
0291 close[i] = possible[i] && next[i] == start_turn_index;
0292 }
0293
0294 if (close[0] != close[1])
0295 {
0296
0297 selected_op_index = close[0] ? 0 : 1;
0298 debug_traverse(turn, turn.operations[selected_op_index], "Candidate cc closing");
0299 return true;
0300 }
0301
0302 if BOOST_GEOMETRY_CONSTEXPR (OverlayType == overlay_buffer)
0303 {
0304 if (possible[0] && possible[1])
0305 {
0306
0307
0308
0309 bool is_target[2] = {0};
0310 for (int i = 0; i < 2; i++)
0311 {
0312 turn_operation_type const& next_op = m_turns[next[i]].operations[i];
0313 is_target[i] = next_op.operation == target_operation;
0314 }
0315
0316 if (is_target[0] != is_target[1])
0317 {
0318
0319 selected_op_index = is_target[0] ? 0 : 1;
0320 debug_traverse(turn, turn.operations[selected_op_index], "Candidate cc target");
0321 return true;
0322 }
0323 }
0324 }
0325
0326 static bool const is_union = target_operation == operation_union;
0327
0328 typename turn_operation_type::comparable_distance_type
0329 best_remaining_distance = 0;
0330
0331 bool result = false;
0332
0333 for (int i = 0; i < 2; i++)
0334 {
0335 if (!possible[i])
0336 {
0337 continue;
0338 }
0339
0340 turn_operation_type const& op = turn.operations[i];
0341
0342 if (! result
0343 || (is_union && op.remaining_distance > best_remaining_distance)
0344 || (!is_union && op.remaining_distance < best_remaining_distance))
0345 {
0346 debug_traverse(turn, op, "First candidate cc", ! result);
0347 debug_traverse(turn, op, "Candidate cc override (remaining)",
0348 result && op.remaining_distance < best_remaining_distance);
0349
0350 selected_op_index = i;
0351 best_remaining_distance = op.remaining_distance;
0352 result = true;
0353 }
0354 }
0355
0356 return result;
0357 }
0358
0359 inline
0360 bool select_noncc_operation(turn_type const& turn,
0361 segment_identifier const& previous_seg_id,
0362 int& selected_op_index) const
0363 {
0364 bool result = false;
0365
0366 for (int i = 0; i < 2; i++)
0367 {
0368 turn_operation_type const& op = turn.operations[i];
0369
0370 if (op.operation == target_operation
0371 && ! op.visited.finished()
0372 && ! op.visited.visited()
0373 && (! result || select_source(turn, op.seg_id, previous_seg_id)))
0374 {
0375 selected_op_index = i;
0376 debug_traverse(turn, op, "Candidate");
0377 result = true;
0378 }
0379 }
0380
0381 return result;
0382 }
0383
0384 inline
0385 bool select_preferred_operation(turn_type const& turn,
0386 signed_size_type turn_index,
0387 signed_size_type start_turn_index,
0388 int& selected_op_index) const
0389 {
0390 bool option[2] = {0};
0391 bool finishing[2] = {0};
0392 bool preferred[2] = {0};
0393 std::size_t shortcut_level[2] = {0};
0394 for (int i = 0; i < 2; i++)
0395 {
0396 turn_operation_type const& op = turn.operations[i];
0397
0398 if (op.operation == target_operation
0399 && ! op.visited.finished()
0400 && ! op.visited.visited())
0401 {
0402 option[i] = true;
0403 if (op.enriched.get_next_turn_index() == start_turn_index)
0404 {
0405 finishing[i] = true;
0406 }
0407 else
0408 {
0409 shortcut_level[i] = get_shortcut_level(op, start_turn_index,
0410 turn_index);
0411 }
0412
0413 if (op.enriched.prefer_start)
0414 {
0415 preferred[i] = true;
0416 }
0417 }
0418 }
0419
0420 if (option[0] != option[1])
0421 {
0422
0423 selected_op_index = option[0] ? 0 : 1;
0424 return true;
0425 }
0426
0427 if (option[0] && option[1])
0428 {
0429
0430 if (finishing[0] != finishing[1])
0431 {
0432
0433 selected_op_index = finishing[0] ? 0 : 1;
0434 return true;
0435 }
0436
0437 if (shortcut_level[0] != shortcut_level[1])
0438 {
0439
0440
0441 selected_op_index = shortcut_level[0] < shortcut_level[1] ? 0 : 1;
0442 return true;
0443 }
0444
0445 if (preferred[0] != preferred[1])
0446 {
0447
0448 selected_op_index = preferred[0] ? 0 : 1;
0449 return true;
0450 }
0451 }
0452
0453 for (int i = 0; i < 2; i++)
0454 {
0455 if (option[i])
0456 {
0457 selected_op_index = 0;
0458 return true;
0459 }
0460 }
0461
0462 return false;
0463 }
0464
0465 inline
0466 bool select_operation(turn_type const& turn,
0467 signed_size_type turn_index,
0468 signed_size_type start_turn_index,
0469 segment_identifier const& previous_seg_id,
0470 int& selected_op_index) const
0471 {
0472 bool result = false;
0473 selected_op_index = -1;
0474 if (turn.both(operation_continue))
0475 {
0476 result = select_cc_operation(turn, start_turn_index,
0477 selected_op_index);
0478 }
0479 else if BOOST_GEOMETRY_CONSTEXPR (OverlayType == overlay_dissolve)
0480 {
0481 result = select_preferred_operation(turn, turn_index,
0482 start_turn_index, selected_op_index);
0483 }
0484 else
0485 {
0486 result = select_noncc_operation(turn, previous_seg_id,
0487 selected_op_index);
0488 }
0489 if (result)
0490 {
0491 debug_traverse(turn, turn.operations[selected_op_index], "Accepted");
0492 }
0493
0494 return result;
0495 }
0496
0497 inline int starting_operation_index(turn_type const& turn) const
0498 {
0499 for (int i = 0; i < 2; i++)
0500 {
0501 if (turn.operations[i].visited.started())
0502 {
0503 return i;
0504 }
0505 }
0506 return -1;
0507 }
0508
0509 inline bool both_finished(turn_type const& turn) const
0510 {
0511 for (int i = 0; i < 2; i++)
0512 {
0513 if (! turn.operations[i].visited.finished())
0514 {
0515 return false;
0516 }
0517 }
0518 return true;
0519 }
0520
0521
0522
0523
0524
0525
0526
0527
0528 inline int priority_of_turn_in_cluster(sort_by_side::rank_type selected_rank,
0529 typename sbs_type::rp const& ranked_point,
0530 cluster_info const& cinfo,
0531 signed_size_type start_turn_index, int start_op_index) const
0532 {
0533 if (ranked_point.rank != selected_rank
0534 || ranked_point.direction != sort_by_side::dir_to)
0535 {
0536 return 0;
0537 }
0538
0539 auto const& turn = m_turns[ranked_point.turn_index];
0540 auto const& op = turn.operations[ranked_point.operation_index];
0541
0542
0543 if (op.visited.finalized())
0544 {
0545 return 0;
0546 }
0547
0548 if BOOST_GEOMETRY_CONSTEXPR (OverlayType != overlay_dissolve)
0549 {
0550 if ((op.enriched.count_left != 0 || op.enriched.count_right == 0) && cinfo.spike_count > 0)
0551 {
0552
0553
0554
0555
0556
0557 return 1;
0558 }
0559 }
0560
0561 bool const to_start = ranked_point.turn_index == start_turn_index;
0562 bool const to_start_index = ranked_point.operation_index == start_op_index;
0563
0564 bool const next_in_same_cluster
0565 = cinfo.turn_indices.count(op.enriched.get_next_turn_index()) > 0;
0566
0567
0568 return to_start && to_start_index ? 5
0569 : to_start ? 4
0570 : next_in_same_cluster ? 2
0571 : 3
0572 ;
0573 }
0574
0575 template <typename RankedPoint>
0576 inline turn_operation_type const& operation_from_rank(RankedPoint const& rp) const
0577 {
0578 return m_turns[rp.turn_index].operations[rp.operation_index];
0579 }
0580
0581 inline sort_by_side::rank_type select_rank(sbs_type const& sbs) const
0582 {
0583 static bool const is_intersection
0584 = target_operation == operation_intersection;
0585
0586
0587
0588 auto const& in_op = operation_from_rank(sbs.m_ranked_points.front());
0589
0590 for (std::size_t i = 0; i < sbs.m_ranked_points.size(); i++)
0591 {
0592 auto const& rp = sbs.m_ranked_points[i];
0593 if (rp.rank == 0 || rp.direction == sort_by_side::dir_from)
0594 {
0595 continue;
0596 }
0597 auto const& out_op = operation_from_rank(rp);
0598
0599 if (out_op.operation != target_operation
0600 && out_op.operation != operation_continue)
0601 {
0602 continue;
0603 }
0604
0605 if (in_op.enriched.region_id == out_op.enriched.region_id
0606 || (is_intersection && ! out_op.enriched.isolated))
0607 {
0608
0609
0610 return rp.rank;
0611 }
0612 }
0613 return -1;
0614 }
0615
0616 inline bool select_from_cluster(signed_size_type& turn_index, int& op_index,
0617 cluster_info const& cinfo, sbs_type const& sbs,
0618 signed_size_type start_turn_index, int start_op_index) const
0619 {
0620 sort_by_side::rank_type const selected_rank = select_rank(sbs);
0621
0622 int current_priority = 0;
0623 for (std::size_t i = 1; i < sbs.m_ranked_points.size(); i++)
0624 {
0625 auto const& ranked_point = sbs.m_ranked_points[i];
0626
0627 if (ranked_point.rank > selected_rank)
0628 {
0629 break;
0630 }
0631
0632 int const priority = priority_of_turn_in_cluster(selected_rank,
0633 ranked_point, cinfo, start_turn_index, start_op_index);
0634
0635 if (priority > current_priority)
0636 {
0637 current_priority = priority;
0638 turn_index = ranked_point.turn_index;
0639 op_index = ranked_point.operation_index;
0640 }
0641 }
0642 return current_priority > 0;
0643 }
0644
0645
0646
0647 inline bool analyze_ii_cluster(signed_size_type& turn_index,
0648 int& op_index, sbs_type const& sbs) const
0649 {
0650
0651 sort_by_side::rank_type const selected_rank = select_rank(sbs);
0652
0653 if (selected_rank <= 0)
0654 {
0655 return false;
0656 }
0657
0658
0659
0660 typename turn_operation_type::comparable_distance_type
0661 min_remaining_distance = 0;
0662
0663 std::size_t selected_index = sbs.m_ranked_points.size();
0664 for (std::size_t i = 0; i < sbs.m_ranked_points.size(); i++)
0665 {
0666 auto const& ranked_point = sbs.m_ranked_points[i];
0667
0668 if (ranked_point.rank > selected_rank)
0669 {
0670 break;
0671 }
0672 else if (ranked_point.rank == selected_rank)
0673 {
0674 auto const& op = operation_from_rank(ranked_point);
0675
0676 if (op.visited.finalized())
0677 {
0678
0679
0680 continue;
0681 }
0682
0683 if (selected_index == sbs.m_ranked_points.size()
0684 || op.remaining_distance < min_remaining_distance)
0685 {
0686
0687 selected_index = i;
0688 min_remaining_distance = op.remaining_distance;
0689 }
0690 }
0691 }
0692
0693 if (selected_index == sbs.m_ranked_points.size())
0694 {
0695
0696 return false;
0697 }
0698
0699 auto const& ranked_point = sbs.m_ranked_points[selected_index];
0700 turn_index = ranked_point.turn_index;
0701 op_index = ranked_point.operation_index;
0702 return true;
0703 }
0704
0705 inline bool fill_sbs(sbs_type& sbs,
0706 signed_size_type turn_index,
0707 std::set<signed_size_type> const& cluster_indices,
0708 segment_identifier const& previous_seg_id) const
0709 {
0710
0711 for (auto cluster_turn_index : cluster_indices)
0712 {
0713 turn_type const& cluster_turn = m_turns[cluster_turn_index];
0714 if (cluster_turn.discarded)
0715 {
0716
0717 continue;
0718 }
0719
0720 for (int i = 0; i < 2; i++)
0721 {
0722 sbs.add(cluster_turn,
0723 cluster_turn.operations[i],
0724 cluster_turn_index, i, previous_seg_id,
0725 m_geometry1, m_geometry2,
0726 cluster_turn_index == turn_index);
0727 }
0728 }
0729
0730 if (! sbs.has_origin())
0731 {
0732 return false;
0733 }
0734 turn_type const& turn = m_turns[turn_index];
0735 sbs.apply(turn.point);
0736 return true;
0737 }
0738
0739
0740 inline bool select_turn_from_cluster(signed_size_type& turn_index,
0741 int& op_index,
0742 signed_size_type start_turn_index, int start_op_index,
0743 segment_identifier const& previous_seg_id) const
0744 {
0745 bool const is_union = target_operation == operation_union;
0746
0747 turn_type const& turn = m_turns[turn_index];
0748 BOOST_ASSERT(turn.is_clustered());
0749
0750 auto mit = m_clusters.find(turn.cluster_id);
0751 BOOST_ASSERT(mit != m_clusters.end());
0752
0753 cluster_info const& cinfo = mit->second;
0754
0755 sbs_type sbs(m_strategy);
0756
0757 if (! fill_sbs(sbs, turn_index, cinfo.turn_indices, previous_seg_id))
0758 {
0759 return false;
0760 }
0761
0762 if BOOST_GEOMETRY_CONSTEXPR (is_union)
0763 {
0764 if (cinfo.open_count == 0 && cinfo.spike_count > 0)
0765 {
0766
0767 for (std::size_t i = 0; i + 1 < sbs.m_ranked_points.size(); i++)
0768 {
0769 auto const& current = sbs.m_ranked_points[i];
0770 auto const& next = sbs.m_ranked_points[i + 1];
0771 if (current.rank == next.rank
0772 && current.direction == detail::overlay::sort_by_side::dir_from
0773 && next.direction == detail::overlay::sort_by_side::dir_to)
0774 {
0775 turn_index = next.turn_index;
0776 op_index = next.operation_index;
0777 return true;
0778 }
0779 }
0780 }
0781 }
0782
0783 return select_from_cluster(turn_index, op_index, cinfo, sbs, start_turn_index, start_op_index);
0784 }
0785
0786
0787
0788
0789
0790 inline bool analyze_ii_intersection(signed_size_type& turn_index, int& op_index,
0791 turn_type const& current_turn,
0792 segment_identifier const& previous_seg_id)
0793 {
0794 sbs_type sbs(m_strategy);
0795
0796
0797 for (int i = 0; i < 2; i++)
0798 {
0799 sbs.add(current_turn,
0800 current_turn.operations[i],
0801 turn_index, i, previous_seg_id,
0802 m_geometry1, m_geometry2,
0803 true);
0804 }
0805
0806 if (! sbs.has_origin())
0807 {
0808 return false;
0809 }
0810
0811 sbs.apply(current_turn.point);
0812
0813 return analyze_ii_cluster(turn_index, op_index, sbs);
0814 }
0815
0816 inline void change_index_for_self_turn(signed_size_type& to_vertex_index,
0817 turn_type const& start_turn,
0818 turn_operation_type const& start_op,
0819 int start_op_index) const
0820 {
0821 if BOOST_GEOMETRY_CONSTEXPR (OverlayType != overlay_buffer
0822 && OverlayType != overlay_dissolve)
0823 {
0824 return;
0825 }
0826 else
0827 {
0828 const bool allow_uu = OverlayType != overlay_buffer;
0829
0830
0831
0832
0833
0834
0835
0836
0837
0838
0839
0840
0841
0842
0843
0844
0845
0846
0847
0848 turn_operation_type const& other_op
0849 = start_turn.operations[1 - start_op_index];
0850
0851 bool const correct
0852 = (allow_uu || ! start_turn.both(operation_union))
0853 && start_op.seg_id.source_index == other_op.seg_id.source_index
0854 && start_op.seg_id.multi_index == other_op.seg_id.multi_index
0855 && start_op.seg_id.ring_index == other_op.seg_id.ring_index
0856 && start_op.seg_id.segment_index == to_vertex_index;
0857
0858 #if defined(BOOST_GEOMETRY_DEBUG_TRAVERSE)
0859 std::cout << " WARNING: self-buffer "
0860 << " correct=" << correct
0861 << " turn=" << operation_char(start_turn.operations[0].operation)
0862 << operation_char(start_turn.operations[1].operation)
0863 << " start=" << start_op.seg_id.segment_index
0864 << " from=" << to_vertex_index
0865 << " to=" << other_op.enriched.travels_to_vertex_index
0866 << std::endl;
0867 #endif
0868
0869 if (correct)
0870 {
0871 to_vertex_index = other_op.enriched.travels_to_vertex_index;
0872 }
0873 }
0874 }
0875
0876 bool select_turn_from_enriched(signed_size_type& turn_index,
0877 segment_identifier& previous_seg_id,
0878 signed_size_type& to_vertex_index,
0879 signed_size_type start_turn_index,
0880 int start_op_index,
0881 turn_type const& previous_turn,
0882 turn_operation_type const& previous_op,
0883 bool is_start) const
0884 {
0885 to_vertex_index = -1;
0886
0887 if (previous_op.enriched.next_ip_index < 0)
0888 {
0889
0890 if (previous_op.enriched.travels_to_vertex_index < 0
0891 || previous_op.enriched.travels_to_ip_index < 0)
0892 {
0893 return false;
0894 }
0895
0896 to_vertex_index = previous_op.enriched.travels_to_vertex_index;
0897
0898 if (is_start &&
0899 previous_op.enriched.travels_to_ip_index == start_turn_index)
0900 {
0901 change_index_for_self_turn(to_vertex_index, previous_turn,
0902 previous_op, start_op_index);
0903 }
0904
0905 turn_index = previous_op.enriched.travels_to_ip_index;
0906 previous_seg_id = previous_op.seg_id;
0907 }
0908 else
0909 {
0910
0911 turn_index = previous_op.enriched.next_ip_index;
0912 previous_seg_id = previous_op.seg_id;
0913 }
0914 return true;
0915 }
0916
0917 bool select_turn(signed_size_type start_turn_index, int start_op_index,
0918 signed_size_type& turn_index,
0919 int& op_index,
0920 int previous_op_index,
0921 signed_size_type previous_turn_index,
0922 segment_identifier const& previous_seg_id,
0923 bool is_start, bool has_points)
0924 {
0925 turn_type const& current_turn = m_turns[turn_index];
0926
0927 bool const back_at_start_cluster
0928 = has_points
0929 && current_turn.is_clustered()
0930 && m_turns[start_turn_index].cluster_id == current_turn.cluster_id;
0931 if BOOST_GEOMETRY_CONSTEXPR (target_operation == operation_intersection)
0932 {
0933
0934
0935 if (has_points && (turn_index == start_turn_index || back_at_start_cluster))
0936 {
0937
0938 turn_index = start_turn_index;
0939 op_index = start_op_index;
0940 return true;
0941 }
0942
0943 if (! current_turn.is_clustered()
0944 && current_turn.both(operation_intersection)
0945 && analyze_ii_intersection(turn_index, op_index,
0946 current_turn, previous_seg_id))
0947 {
0948 return true;
0949 }
0950 }
0951 else if (turn_index == start_turn_index || back_at_start_cluster)
0952 {
0953
0954
0955 auto const& current_op = current_turn.operations[op_index];
0956 signed_size_type const next_turn_index = current_op.enriched.get_next_turn_index();
0957 bool const to_other_turn = next_turn_index >= 0 && m_turns[next_turn_index].cluster_id != current_turn.cluster_id;
0958 if (! to_other_turn)
0959 {
0960
0961 turn_index = start_turn_index;
0962 op_index = start_op_index;
0963 return true;
0964 }
0965 }
0966
0967 if (current_turn.is_clustered())
0968 {
0969 if (! select_turn_from_cluster(turn_index, op_index,
0970 start_turn_index, start_op_index, previous_seg_id))
0971 {
0972 return false;
0973 }
0974
0975 if (is_start && turn_index == previous_turn_index)
0976 {
0977 op_index = previous_op_index;
0978 }
0979 }
0980 else
0981 {
0982 op_index = starting_operation_index(current_turn);
0983 if (op_index == -1)
0984 {
0985 if (both_finished(current_turn))
0986 {
0987 return false;
0988 }
0989
0990 if (! select_operation(current_turn, turn_index,
0991 start_turn_index,
0992 previous_seg_id,
0993 op_index))
0994 {
0995 return false;
0996 }
0997 }
0998 }
0999 return true;
1000 }
1001
1002 private :
1003 Geometry1 const& m_geometry1;
1004 Geometry2 const& m_geometry2;
1005 Turns& m_turns;
1006 Clusters const& m_clusters;
1007 Strategy m_strategy;
1008 Visitor& m_visitor;
1009 };
1010
1011
1012 }}
1013 #endif
1014
1015 }}
1016
1017 #endif