diff options
author | DongHun Kwak <dh0128.kwak@samsung.com> | 2017-09-13 11:24:46 +0900 |
---|---|---|
committer | DongHun Kwak <dh0128.kwak@samsung.com> | 2017-09-13 11:25:39 +0900 |
commit | 4fadd968fa12130524c8380f33fcfe25d4de79e5 (patch) | |
tree | fd26a490cd15388d42fc6652b3c5c13012e7f93e /boost/geometry/algorithms/detail/overlay/traversal.hpp | |
parent | b5c87084afaef42b2d058f68091be31988a6a874 (diff) | |
download | boost-4fadd968fa12130524c8380f33fcfe25d4de79e5.tar.gz boost-4fadd968fa12130524c8380f33fcfe25d4de79e5.tar.bz2 boost-4fadd968fa12130524c8380f33fcfe25d4de79e5.zip |
Imported Upstream version 1.65.0upstream/1.65.0
Change-Id: Icf8400b375482cb11bcf77440a6934ba360d6ba4
Signed-off-by: DongHun Kwak <dh0128.kwak@samsung.com>
Diffstat (limited to 'boost/geometry/algorithms/detail/overlay/traversal.hpp')
-rw-r--r-- | boost/geometry/algorithms/detail/overlay/traversal.hpp | 434 |
1 files changed, 241 insertions, 193 deletions
diff --git a/boost/geometry/algorithms/detail/overlay/traversal.hpp b/boost/geometry/algorithms/detail/overlay/traversal.hpp index bc828920e9..69d62b788b 100644 --- a/boost/geometry/algorithms/detail/overlay/traversal.hpp +++ b/boost/geometry/algorithms/detail/overlay/traversal.hpp @@ -2,6 +2,11 @@ // Copyright (c) 2007-2012 Barend Gehrels, Amsterdam, the Netherlands. +// This file was modified by Oracle on 2017. +// Modifications copyright (c) 2017 Oracle and/or its affiliates. + +// Contributed and/or modified by Adam Wulkiewicz, on behalf of Oracle + // Use, modification and distribution is subject to the Boost Software License, // Version 1.0. (See accompanying file LICENSE_1_0.txt or copy at // http://www.boost.org/LICENSE_1_0.txt) @@ -14,7 +19,9 @@ #include <boost/range.hpp> #include <boost/geometry/algorithms/detail/overlay/aggregate_operations.hpp> +#include <boost/geometry/algorithms/detail/overlay/is_self_turn.hpp> #include <boost/geometry/algorithms/detail/overlay/sort_by_side.hpp> +#include <boost/geometry/algorithms/detail/overlay/traversal_intersection_patterns.hpp> #include <boost/geometry/algorithms/detail/overlay/turn_info.hpp> #include <boost/geometry/core/access.hpp> #include <boost/geometry/core/assert.hpp> @@ -37,9 +44,13 @@ namespace detail { namespace overlay template <typename Turn, typename Operation> #ifdef BOOST_GEOMETRY_DEBUG_TRAVERSE inline void debug_traverse(Turn const& turn, Operation op, - std::string const& header) + std::string const& header, bool condition = true) { - std::cout << header + if (! condition) + { + return; + } + std::cout << " " << header << " at " << op.seg_id << " meth: " << method_char(turn.method) << " op: " << operation_char(op.operation) @@ -55,7 +66,7 @@ inline void debug_traverse(Turn const& turn, Operation op, } } #else -inline void debug_traverse(Turn const& , Operation, const char*) +inline void debug_traverse(Turn const& , Operation, const char*, bool = true) { } #endif @@ -88,6 +99,7 @@ template typename Turns, typename Clusters, typename RobustPolicy, + typename SideStrategy, typename Visitor > struct traversal @@ -101,18 +113,20 @@ struct traversal typedef typename geometry::point_type<Geometry1>::type point_type; typedef sort_by_side::side_sorter < - Reverse1, Reverse2, - point_type, side_compare_type + Reverse1, Reverse2, OverlayType, + point_type, SideStrategy, side_compare_type > sbs_type; inline traversal(Geometry1 const& geometry1, Geometry2 const& geometry2, Turns& turns, Clusters const& clusters, - RobustPolicy const& robust_policy, Visitor& visitor) + RobustPolicy const& robust_policy, SideStrategy const& strategy, + Visitor& visitor) : m_geometry1(geometry1) , m_geometry2(geometry2) , m_turns(turns) , m_clusters(clusters) , m_robust_policy(robust_policy) + , m_strategy(strategy) , m_visitor(visitor) { } @@ -133,11 +147,38 @@ struct traversal } } + //! Sets visited for ALL turns traveling to the same turn + inline void set_visited_in_cluster(signed_size_type cluster_id, + signed_size_type rank) + { + typename Clusters::const_iterator mit = m_clusters.find(cluster_id); + BOOST_ASSERT(mit != m_clusters.end()); + + cluster_info const& cinfo = mit->second; + std::set<signed_size_type> const& ids = cinfo.turn_indices; + + for (typename std::set<signed_size_type>::const_iterator it = ids.begin(); + it != ids.end(); ++it) + { + signed_size_type const turn_index = *it; + turn_type& turn = m_turns[turn_index]; + + for (int i = 0; i < 2; i++) + { + turn_operation_type& op = turn.operations[i]; + if (op.visited.none() + && op.enriched.rank == rank) + { + op.visited.set_visited(); + } + } + } + } inline void set_visited(turn_type& turn, turn_operation_type& op) { - // On "continue", set "visited" for ALL directions in this turn if (op.operation == detail::overlay::operation_continue) { + // On "continue", all go in same direction so set "visited" for ALL for (int i = 0; i < 2; i++) { turn_operation_type& turn_op = turn.operations[i]; @@ -151,6 +192,10 @@ struct traversal { op.visited.set_visited(); } + if (turn.cluster_id >= 0) + { + set_visited_in_cluster(turn.cluster_id, op.enriched.rank); + } } inline bool is_visited(turn_type const& , turn_operation_type const& op, @@ -160,8 +205,8 @@ struct traversal } inline bool select_source(signed_size_type turn_index, - segment_identifier const& seg_id1, - segment_identifier const& seg_id2) const + segment_identifier const& candidate_seg_id, + segment_identifier const& previous_seg_id) const { // For uu/ii, only switch sources if indicated turn_type const& turn = m_turns[turn_index]; @@ -170,8 +215,16 @@ struct traversal { // Buffer does not use source_index (always 0) return turn.switch_source - ? seg_id1.multi_index != seg_id2.multi_index - : seg_id1.multi_index == seg_id2.multi_index; + ? candidate_seg_id.multi_index != previous_seg_id.multi_index + : candidate_seg_id.multi_index == previous_seg_id.multi_index; + } + + if (is_self_turn<OverlayType>(turn)) + { + // Also, if it is a self-turn, stay on same ring (multi/ring) + return turn.switch_source + ? candidate_seg_id.multi_index != previous_seg_id.multi_index + : candidate_seg_id.multi_index == previous_seg_id.multi_index; } #if defined(BOOST_GEOMETRY_DEBUG_TRAVERSAL_SWITCH_DETECTOR) @@ -185,16 +238,8 @@ struct traversal } #endif return turn.switch_source - ? seg_id1.source_index != seg_id2.source_index - : seg_id1.source_index == seg_id2.source_index; - } - - inline - signed_size_type get_next_turn_index(turn_operation_type const& op) const - { - return op.enriched.next_ip_index == -1 - ? op.enriched.travels_to_ip_index - : op.enriched.next_ip_index; + ? candidate_seg_id.source_index != previous_seg_id.source_index + : candidate_seg_id.source_index == previous_seg_id.source_index; } inline bool traverse_possible(signed_size_type turn_index) const @@ -220,39 +265,39 @@ struct traversal { // For "cc", take either one, but if there is a starting one, // take that one. If next is dead end, skip that one. + // If both are valid candidates, take the one with minimal remaining + // distance (important for #mysql_23023665 in buffer). - bool result = false; - + // Initialize with 0, automatically assigned on first result typename turn_operation_type::comparable_distance_type - max_remaining_distance = 0; + min_remaining_distance = 0; + + bool result = false; for (int i = 0; i < 2; i++) { turn_operation_type const& op = turn.operations[i]; - signed_size_type const next_turn_index = get_next_turn_index(op); + signed_size_type const next_turn_index = op.enriched.get_next_turn_index(); - if (! result && traverse_possible(next_turn_index)) + if (! traverse_possible(next_turn_index)) { - max_remaining_distance = op.remaining_distance; - selected_op_index = i; - debug_traverse(turn, op, " Candidate"); - result = true; + continue; } - if (result) + if (! result + || next_turn_index == start_turn_index + || op.remaining_distance < min_remaining_distance) { - if (next_turn_index == start_turn_index) - { - selected_op_index = i; - debug_traverse(turn, op, " Candidate cc override (start)"); - } - else if (op.remaining_distance > max_remaining_distance) - { - max_remaining_distance = op.remaining_distance; - selected_op_index = i; - debug_traverse(turn, op, " Candidate cc override (remaining)"); - } + debug_traverse(turn, op, "First candidate cc", ! result); + debug_traverse(turn, op, "Candidate cc override (start)", + result && next_turn_index == start_turn_index); + debug_traverse(turn, op, "Candidate cc override (remaining)", + result && op.remaining_distance < min_remaining_distance); + + selected_op_index = i; + min_remaining_distance = op.remaining_distance; + result = true; } } @@ -262,7 +307,7 @@ struct traversal inline bool select_noncc_operation(turn_type const& turn, signed_size_type turn_index, - segment_identifier const& seg_id, + segment_identifier const& previous_seg_id, int& selected_op_index) const { bool result = false; @@ -273,10 +318,10 @@ struct traversal if (op.operation == target_operation && ! op.visited.finished() - && (! result || select_source(turn_index, op.seg_id, seg_id))) + && (! result || select_source(turn_index, op.seg_id, previous_seg_id))) { selected_op_index = i; - debug_traverse(turn, op, " Candidate"); + debug_traverse(turn, op, "Candidate"); result = true; } } @@ -305,7 +350,7 @@ struct traversal } if (result) { - debug_traverse(turn, turn.operations[selected_op_index], " Accepted"); + debug_traverse(turn, turn.operations[selected_op_index], "Accepted"); } return result; @@ -336,108 +381,164 @@ struct traversal } inline bool select_from_cluster_union(signed_size_type& turn_index, - int& op_index, signed_size_type start_turn_index, - sbs_type const& sbs, bool is_touching) const + int& op_index, sbs_type& sbs) const { + std::vector<sort_by_side::rank_with_rings> aggregation; + sort_by_side::aggregate_operations(sbs, aggregation, m_turns, operation_union); + + + sort_by_side::rank_with_rings const& incoming = aggregation.front(); + + // Take the first one outgoing for the incoming region std::size_t selected_rank = 0; - std::size_t min_rank = 0; - bool result = false; - for (std::size_t i = 0; i < sbs.m_ranked_points.size(); i++) + for (std::size_t i = 1; i < aggregation.size(); i++) + { + sort_by_side::rank_with_rings const& rwr = aggregation[i]; + if (rwr.all_to() + && rwr.region_id() == incoming.region_id()) + { + selected_rank = rwr.rank; + break; + } + } + + for (std::size_t i = 1; i < sbs.m_ranked_points.size(); i++) { typename sbs_type::rp const& ranked_point = sbs.m_ranked_points[i]; - if (result && ranked_point.rank > selected_rank) + if (ranked_point.rank == selected_rank + && ranked_point.direction == sort_by_side::dir_to) { - return result; + turn_index = ranked_point.turn_index; + op_index = ranked_point.operation_index; + + turn_type const& turn = m_turns[turn_index]; + turn_operation_type const& op = turn.operations[op_index]; + + if (op.enriched.count_left == 0 + && op.enriched.count_right > 0 + && ! op.visited.finalized()) + { + // In some cases interior rings might be generated with polygons + // on both sides + + // TODO: this should be finetuned such that checking + // finalized is not necessary + return true; + } } + } + return false; + } - turn_type const& ranked_turn = m_turns[ranked_point.turn_index]; - turn_operation_type const& ranked_op = ranked_turn.operations[ranked_point.operation_index]; - if (result && ranked_op.visited.finalized()) + inline bool all_operations_of_type(sort_by_side::rank_with_rings const& rwr, + operation_type op_type, + sort_by_side::direction_type dir) const + { + typedef std::set<sort_by_side::ring_with_direction>::const_iterator sit_type; + for (sit_type it = rwr.rings.begin(); it != rwr.rings.end(); ++it) + { + sort_by_side::ring_with_direction const& rwd = *it; + if (rwd.direction != dir) { - // One of the arcs in the same direction as the selected result - // is already traversed. return false; } - - if (! is_touching && ranked_op.visited.finalized()) + turn_type const& turn = m_turns[rwd.turn_index]; + if (! turn.both(op_type)) { - // Skip this one, go to next - min_rank = ranked_point.rank; - continue; + return false; } - if (ranked_point.direction == sort_by_side::dir_to - && (ranked_point.rank > min_rank - || ranked_turn.both(operation_continue))) + // Check if this is not yet taken + turn_operation_type const& op = turn.operations[rwd.operation_index]; + if (op.visited.finalized()) { - if (ranked_op.enriched.count_left == 0 - && ranked_op.enriched.count_right > 0) - { - if (result && ranked_point.turn_index != start_turn_index) - { - // Don't override - only override if arrive at start - continue; - } - - turn_index = ranked_point.turn_index; - op_index = ranked_point.operation_index; - - result = true; - selected_rank = ranked_point.rank; - } - else if (! is_touching) - { - return result; - } + return false; } + } - return result; + return true; } inline bool analyze_cluster_intersection(signed_size_type& turn_index, - int& op_index, - sbs_type const& sbs) const + int& op_index, sbs_type const& sbs) const { std::vector<sort_by_side::rank_with_rings> aggregation; - sort_by_side::aggregate_operations(sbs, aggregation); + sort_by_side::aggregate_operations(sbs, aggregation, m_turns, operation_intersection); std::size_t selected_rank = 0; - for (std::size_t i = 0; i < aggregation.size(); i++) + + // Detect specific pattern(s) + bool const detected + = intersection_pattern_common_interior1(selected_rank, aggregation) + || intersection_pattern_common_interior2(selected_rank, aggregation) + || intersection_pattern_common_interior3(selected_rank, aggregation) + || intersection_pattern_common_interior4(selected_rank, aggregation) + ; + + if (! detected) { - sort_by_side::rank_with_rings const& rwr = aggregation[i]; + int incoming_region_id = 0; + std::set<int> outgoing_region_ids; - if (i > 1 - && i - 1 == selected_rank - && rwr.rings.size() == 1) + for (std::size_t i = 0; i < aggregation.size(); i++) { - sort_by_side::ring_with_direction const& rwd = *rwr.rings.begin(); + sort_by_side::rank_with_rings const& rwr = aggregation[i]; - if (rwd.only_turn_on_ring) + if (rwr.all_to() + && rwr.traversable(m_turns) + && selected_rank == 0) { - // Find if this arriving ring was leaving previously - sort_by_side::ring_with_direction leaving = rwd; - leaving.direction = sort_by_side::dir_to; - - sort_by_side::rank_with_rings const& previous = aggregation[i - 1]; + // Take the first (= right) where segments leave, + // having the polygon on the right side + selected_rank = rwr.rank; + } - if (previous.rings.size() == 1 - && previous.rings.count(leaving) == 1) - { - // It arrives back - if this is one of the selected, unselect it - selected_rank = 0; - } + if (rwr.all_from() + && selected_rank > 0 + && outgoing_region_ids.empty()) + { + // Incoming + break; } - } - if (rwr.all_to()) - { - if (selected_rank == 0) + if (incoming_region_id == 0) { - // Take the first (= right) where segments leave, - // having the polygon on the right side - selected_rank = rwr.rank; + sort_by_side::ring_with_direction const& rwd = *rwr.rings.begin(); + turn_type const& turn = m_turns[rwd.turn_index]; + incoming_region_id = turn.operations[rwd.operation_index].enriched.region_id; + } + else + { + if (rwr.rings.size() == 1) + { + sort_by_side::ring_with_direction const& rwd = *rwr.rings.begin(); + turn_type const& turn = m_turns[rwd.turn_index]; + if (rwd.direction == sort_by_side::dir_to + && turn.both(operation_intersection)) + { + + turn_operation_type const& op = turn.operations[rwd.operation_index]; + if (op.enriched.region_id != incoming_region_id + && op.enriched.isolated) + { + outgoing_region_ids.insert(op.enriched.region_id); + } + } + else if (! outgoing_region_ids.empty()) + { + for (int i = 0; i < 2; i++) + { + int const region_id = turn.operations[i].enriched.region_id; + if (outgoing_region_ids.count(region_id) == 1) + { + selected_rank = 0; + outgoing_region_ids.erase(region_id); + } + } + } + } } } } @@ -458,7 +559,7 @@ struct traversal { // This direction is already traveled before, the same // cannot be traveled again - return false; + continue; } // Take the last turn from this rank @@ -479,10 +580,9 @@ struct traversal } inline bool select_turn_from_cluster(signed_size_type& turn_index, - int& op_index, bool& is_touching, + int& op_index, signed_size_type start_turn_index, - segment_identifier const& previous_seg_id, - bool is_start) const + segment_identifier const& previous_seg_id) const { bool const is_union = target_operation == operation_union; @@ -495,15 +595,14 @@ struct traversal cluster_info const& cinfo = mit->second; std::set<signed_size_type> const& ids = cinfo.turn_indices; - sbs_type sbs; - - bool has_origin = false; + sbs_type sbs(m_strategy); for (typename std::set<signed_size_type>::const_iterator sit = ids.begin(); sit != ids.end(); ++sit) { signed_size_type cluster_turn_index = *sit; turn_type const& cluster_turn = m_turns[cluster_turn_index]; + bool const departure_turn = cluster_turn_index == turn_index; if (cluster_turn.discarded) { // Defensive check, discarded turns should not be in cluster @@ -512,79 +611,27 @@ struct traversal for (int i = 0; i < 2; i++) { - turn_operation_type const& op = cluster_turn.operations[i]; - bool is_origin = false; - if (cluster_turn_index == turn_index) - { - // Check if this is the origin - if (OverlayType == overlay_buffer) - { - is_origin = op.seg_id.multi_index == previous_seg_id.multi_index; - } - else - { - is_origin = op.seg_id.source_index - == previous_seg_id.source_index; - } - if (is_origin) - { - has_origin = true; - } - } - - sbs.add(op, cluster_turn_index, i, m_geometry1, m_geometry2, - is_origin); + sbs.add(cluster_turn.operations[i], + cluster_turn_index, i, previous_seg_id, + m_geometry1, m_geometry2, + departure_turn); } } - if (! has_origin) + if (! sbs.has_origin()) { return false; } - sbs.apply(turn.point); bool result = false; if (is_union) { - #if defined(BOOST_GEOMETRY_DEBUG_TRAVERSAL_SWITCH_DETECTOR) - is_touching = cinfo.open_count > 1; - if (is_touching) - { - if (cinfo.switch_source) - { - is_touching = false; - std::cout << "CLUSTER: SWITCH SOURCES at " << turn_index << std::endl; - } - else - { - std::cout << "CLUSTER: CONTINUE at " << turn_index << std::endl; - } - } - #else - is_touching = cinfo.open_count > 1 && ! cinfo.switch_source; - #endif - - if (is_touching) - { - sbs.reverse(); - } - - result = select_from_cluster_union(turn_index, op_index, start_turn_index, sbs, - is_touching); + result = select_from_cluster_union(turn_index, op_index, sbs); } else { - if (is_start - && turn.both(operation_intersection) - && turn.operations[op_index].enriched.only_turn_on_ring) - { - // For an ii (usually interior ring), only turn on ring, - // reverse to take first exit - sbs.reverse(); - } - result = analyze_cluster_intersection(turn_index, op_index, sbs); } return result; @@ -594,26 +641,27 @@ struct traversal turn_type const& current_turn, segment_identifier const& previous_seg_id) { - sbs_type sbs; + sbs_type sbs(m_strategy); // Add this turn to the sort-by-side sorter - bool has_origin = false; for (int i = 0; i < 2; i++) { - turn_operation_type const& op = current_turn.operations[i]; - bool const is_origin = op.seg_id.source_index - == previous_seg_id.source_index; - has_origin = has_origin || is_origin; - sbs.add(op, turn_index, i, m_geometry1, m_geometry2, is_origin); + sbs.add(current_turn.operations[i], + turn_index, i, previous_seg_id, + m_geometry1, m_geometry2, + true); } - if (! has_origin) + if (! sbs.has_origin()) { return false; } sbs.apply(current_turn.point); - return analyze_cluster_intersection(turn_index, op_index, sbs); + + bool result = analyze_cluster_intersection(turn_index, op_index, sbs); + + return result; } inline void change_index_for_self_turn(signed_size_type& to_vertex_index, @@ -712,7 +760,6 @@ struct traversal bool select_turn(signed_size_type start_turn_index, int start_op_index, signed_size_type& turn_index, int& op_index, - bool& is_touching, int previous_op_index, signed_size_type previous_turn_index, segment_identifier const& previous_seg_id, @@ -737,8 +784,8 @@ struct traversal if (current_turn.cluster_id < 0 && current_turn.both(operation_intersection)) { - if (analyze_ii_intersection(turn_index, op_index, current_turn, - previous_seg_id)) + if (analyze_ii_intersection(turn_index, op_index, + current_turn, previous_seg_id)) { return true; } @@ -747,8 +794,8 @@ struct traversal if (current_turn.cluster_id >= 0) { - if (! select_turn_from_cluster(turn_index, op_index, is_touching, - start_turn_index, previous_seg_id, is_start)) + if (! select_turn_from_cluster(turn_index, op_index, + start_turn_index, previous_seg_id)) { return false; } @@ -786,6 +833,7 @@ private : Turns& m_turns; Clusters const& m_clusters; RobustPolicy const& m_robust_policy; + SideStrategy m_strategy; Visitor& m_visitor; }; |