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