From 5d99d1608db76a5f8380bb4c71ad0d0c4e42e7f4 Mon Sep 17 00:00:00 2001 From: Barend Gehrels Date: Fri, 15 Dec 2017 13:20:41 +0100 Subject: [PATCH] [overlay] fix new #case_recursive_boxes_82 by greatly simplifying the code. patterns/aggregations were added to solve specific intersection problems and validity in the past. In the meantime self-turns and isolation information is much better, and those code is not needed anymore. This also fixes the #mysql_regression_1_65_2017_08_31 This also makes union/intersection code for handling clusters much more similar --- .../detail/overlay/aggregate_operations.hpp | 256 ---------- .../algorithms/detail/overlay/traversal.hpp | 120 +---- .../traversal_intersection_patterns.hpp | 451 ------------------ .../overlay/multi_overlay_cases.hpp | 8 + .../difference/difference_multi.cpp | 5 - .../intersection/intersection_multi.cpp | 5 + 6 files changed, 36 insertions(+), 809 deletions(-) delete mode 100644 include/boost/geometry/algorithms/detail/overlay/aggregate_operations.hpp delete mode 100644 include/boost/geometry/algorithms/detail/overlay/traversal_intersection_patterns.hpp diff --git a/include/boost/geometry/algorithms/detail/overlay/aggregate_operations.hpp b/include/boost/geometry/algorithms/detail/overlay/aggregate_operations.hpp deleted file mode 100644 index 3f2aea1b1..000000000 --- a/include/boost/geometry/algorithms/detail/overlay/aggregate_operations.hpp +++ /dev/null @@ -1,256 +0,0 @@ -// Boost.Geometry (aka GGL, Generic Geometry Library) - -// Copyright (c) 2016 Barend Gehrels, Amsterdam, the Netherlands. - -// 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) - -#ifndef BOOST_GEOMETRY_ALGORITHMS_DETAIL_OVERLAY_AGGREGATE_OPERATIONS_HPP -#define BOOST_GEOMETRY_ALGORITHMS_DETAIL_OVERLAY_AGGREGATE_OPERATIONS_HPP - -#include - -#include - -namespace boost { namespace geometry -{ - -#ifndef DOXYGEN_NO_DETAIL -namespace detail { namespace overlay { namespace sort_by_side -{ - -struct ring_with_direction -{ - ring_identifier ring_id; - direction_type direction; - - signed_size_type turn_index; - int operation_index; - operation_type operation; - signed_size_type region_id; - bool isolated; - - inline bool operator<(ring_with_direction const& other) const - { - return this->ring_id != other.ring_id - ? this->ring_id < other.ring_id - : this->direction < other.direction; - } - - ring_with_direction() - : direction(dir_unknown) - , turn_index(-1) - , operation_index(0) - , operation(operation_none) - , region_id(-1) - , isolated(false) - {} -}; - -struct rank_with_rings -{ - // Define a set having a ring, with its direction (from/to). Each ring - // arrive at / leaves a cluster only once. TODO: this is not true for - // invalid ring. The rank needs to be considered too. - typedef std::set container_type; - std::size_t rank; - container_type rings; - - rank_with_rings() - : rank(0) - { - } - - inline bool all_equal(direction_type dir_type) const - { - for (container_type::const_iterator it = rings.begin(); - it != rings.end(); ++it) - { - if (it->direction != dir_type) - { - return false; - } - } - return true; - } - - inline bool all_to() const - { - return all_equal(sort_by_side::dir_to); - } - - inline bool all_from() const - { - return all_equal(sort_by_side::dir_from); - } - - inline bool has_only(operation_type op) const - { - for (container_type::const_iterator it = rings.begin(); - it != rings.end(); ++it) - { - const ring_with_direction& rwd = *it; - if (rwd.operation != op) - { - return false; - } - } - return true; - } - - //! Check if set has both op1 and op2, but no others - inline bool has_only_both(operation_type op1, operation_type op2) const - { - bool has1 = false; - bool has2 = false; - for (container_type::const_iterator it = rings.begin(); - it != rings.end(); ++it) - { - const ring_with_direction& rwd = *it; - - if (rwd.operation == op1) { has1 = true; } - else if (rwd.operation == op2) { has2 = true; } - else { return false; } - } - return has1 && has2; - } - - inline bool is_isolated() const - { - for (container_type::const_iterator it = rings.begin(); - it != rings.end(); ++it) - { - const ring_with_direction& rwd = *it; - if (! rwd.isolated) - { - return false; - } - } - return true; - } - - inline bool has_unique_region_id() const - { - signed_size_type region_id = -1; - for (container_type::const_iterator it = rings.begin(); - it != rings.end(); ++it) - { - const ring_with_direction& rwd = *it; - if (region_id == -1) - { - region_id = rwd.region_id; - } - else if (rwd.region_id != region_id) - { - return false; - } - } - return true; - } - - inline signed_size_type region_id() const - { - signed_size_type region_id = -1; - for (container_type::const_iterator it = rings.begin(); - it != rings.end(); ++it) - { - const ring_with_direction& rwd = *it; - if (region_id == -1) - { - region_id = rwd.region_id; - } - else if (rwd.region_id != region_id) - { - return -1; - } - } - return region_id; - } - - template - inline bool traversable(Turns const& turns) const - { - typedef typename boost::range_value::type turn_type; - typedef typename turn_type::turn_operation_type turn_operation_type; - - for (container_type::const_iterator it = rings.begin(); - it != rings.end(); ++it) - { - const ring_with_direction& rwd = *it; - turn_type const& turn = turns[rwd.turn_index]; - turn_operation_type const& op = turn.operations[rwd.operation_index]; - - // TODO: this is still necessary, but makes it order-dependent - // which should not be done. - - // This would obsolete the whole function and should be solved - // in a different way - if (op.visited.finalized() || op.visited.visited()) - { - return false; - } - } - return true; - } - -}; - -template -inline void aggregate_operations(Sbs const& sbs, std::vector& aggregation, - Turns const& turns, - operation_type target_operation) -{ - typedef typename boost::range_value::type turn_type; - typedef typename turn_type::turn_operation_type turn_operation_type; - - aggregation.clear(); - for (std::size_t i = 0; i < sbs.m_ranked_points.size(); i++) - { - typename Sbs::rp const& ranked_point = sbs.m_ranked_points[i]; - - turn_type const& turn = turns[ranked_point.turn_index]; - - turn_operation_type const& op = turn.operations[ranked_point.operation_index]; - - if (! ((target_operation == operation_union && ranked_point.rank == 0) - || op.operation == target_operation - || op.operation == operation_continue - || (op.operation == operation_blocked && ranked_point.direction == dir_from))) - { - // Always take rank 0 (because self-turns are blocked) - // Don't consider union/blocked (aggregate is only used for intersections) - // Blocked is allowed for from - continue; - } - - if (aggregation.empty() || aggregation.back().rank != ranked_point.rank) - { - rank_with_rings current; - current.rank = ranked_point.rank; - aggregation.push_back(current); - } - - ring_with_direction rwd; - segment_identifier const& sid = ranked_point.seg_id; - - rwd.ring_id = ring_identifier(sid.source_index, sid.multi_index, sid.ring_index); - rwd.direction = ranked_point.direction; - rwd.turn_index = ranked_point.turn_index; - rwd.operation_index = ranked_point.operation_index; - rwd.operation = op.operation; - rwd.region_id = op.enriched.region_id; - rwd.isolated = op.enriched.isolated; - - aggregation.back().rings.insert(rwd); - } -} - - -}}} // namespace detail::overlay::sort_by_side -#endif //DOXYGEN_NO_DETAIL - - -}} // namespace boost::geometry - -#endif // BOOST_GEOMETRY_ALGORITHMS_DETAIL_OVERLAY_AGGREGATE_OPERATIONS_HPP diff --git a/include/boost/geometry/algorithms/detail/overlay/traversal.hpp b/include/boost/geometry/algorithms/detail/overlay/traversal.hpp index 732a03164..75807a203 100644 --- a/include/boost/geometry/algorithms/detail/overlay/traversal.hpp +++ b/include/boost/geometry/algorithms/detail/overlay/traversal.hpp @@ -18,10 +18,8 @@ #include -#include #include #include -#include #include #include #include @@ -459,21 +457,19 @@ struct traversal } template - inline signed_size_type region_from_rank(RankedPoint const& rp) const + inline turn_operation_type const& operation_from_rank(RankedPoint const& rp) const { - turn_operation_type const& op = m_turns[rp.turn_index].operations[rp.operation_index]; - return op.enriched.region_id; + return m_turns[rp.turn_index].operations[rp.operation_index]; } - inline bool select_from_cluster_union(signed_size_type& turn_index, - int& op_index, sbs_type& sbs, - signed_size_type start_turn_index, int start_op_index) const + inline signed_size_type select_rank(sbs_type const& sbs, + bool skip_isolated) const { - // Take the first outgoing rank corresponding to incoming region - signed_size_type const incoming_region - = region_from_rank(sbs.m_ranked_points.front()); + // Take the first outgoing rank corresponding to incoming region, + // or take another region if it is not isolated + turn_operation_type const& incoming_op + = operation_from_rank(sbs.m_ranked_points.front()); - std::size_t selected_rank = 0; for (std::size_t i = 0; i < sbs.m_ranked_points.size(); i++) { typename sbs_type::rp const& rp = sbs.m_ranked_points[i]; @@ -481,14 +477,24 @@ struct traversal { continue; } - signed_size_type const region = region_from_rank(rp); + turn_operation_type const& op = operation_from_rank(rp); - if (region == incoming_region) + if (op.enriched.region_id == incoming_op.enriched.region_id + || (skip_isolated && ! op.enriched.isolated)) { - selected_rank = rp.rank; - break; + // Region corresponds to incoming region, or (for intersection) + // there is a non-isolated other region which should be taken + return rp.rank; } } + return -1; + } + + inline bool select_from_cluster_union(signed_size_type& turn_index, + int& op_index, sbs_type const& sbs, + signed_size_type start_turn_index, int start_op_index) const + { + std::size_t const selected_rank = select_rank(sbs, false); int best_code = 0; bool result = false; @@ -521,87 +527,7 @@ struct traversal inline bool analyze_cluster_intersection(signed_size_type& turn_index, int& op_index, sbs_type const& sbs) const { - std::vector aggregation; - sort_by_side::aggregate_operations(sbs, aggregation, m_turns, operation_intersection); - - std::size_t selected_rank = 0; - - - // 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) - || intersection_pattern_common_interior5(selected_rank, aggregation) - || intersection_pattern_common_interior6(selected_rank, aggregation) - ; - - if (! detected) - { - signed_size_type incoming_region_id = 0; - std::set outgoing_region_ids; - - for (std::size_t i = 0; i < aggregation.size(); i++) - { - sort_by_side::rank_with_rings const& rwr = aggregation[i]; - - if (rwr.all_to() - && rwr.traversable(m_turns) - && selected_rank == 0) - { - // Take the first (= right) where segments leave, - // having the polygon on the right side - selected_rank = rwr.rank; - } - - if (rwr.all_from() - && selected_rank > 0 - && outgoing_region_ids.empty()) - { - // Incoming - break; - } - - if (incoming_region_id == 0) - { - 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++) - { - signed_size_type 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); - } - } - } - } - } - } - } + std::size_t const selected_rank = select_rank(sbs, true); if (selected_rank > 0) { diff --git a/include/boost/geometry/algorithms/detail/overlay/traversal_intersection_patterns.hpp b/include/boost/geometry/algorithms/detail/overlay/traversal_intersection_patterns.hpp deleted file mode 100644 index a8abea230..000000000 --- a/include/boost/geometry/algorithms/detail/overlay/traversal_intersection_patterns.hpp +++ /dev/null @@ -1,451 +0,0 @@ -// Boost.Geometry (aka GGL, Generic Geometry Library) - -// Copyright (c) 2007-2017 Barend Gehrels, Amsterdam, the Netherlands. - -// 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) - -#ifndef BOOST_GEOMETRY_ALGORITHMS_DETAIL_OVERLAY_TRAVERSAL_INTERSECTION_PATTERNS_HPP -#define BOOST_GEOMETRY_ALGORITHMS_DETAIL_OVERLAY_TRAVERSAL_INTERSECTION_PATTERNS_HPP - -#include -#include - -#include -#include - -namespace boost { namespace geometry -{ - -#ifndef DOXYGEN_NO_DETAIL -namespace detail { namespace overlay -{ - -inline bool check_pairs(std::vector const& aggregation, - signed_size_type incoming_region_id, - std::size_t first, std::size_t last) -{ - // Check if pairs 1,2 (and possibly 3,4 and 5,6 etc) satisfy - - for (std::size_t i = first; i <= last; i += 2) - { - sort_by_side::rank_with_rings const& curr = aggregation[i]; - sort_by_side::rank_with_rings const& next = aggregation[i + 1]; - signed_size_type const curr_id = curr.region_id(); - signed_size_type const next_id = next.region_id(); - - bool const possible = - curr.rings.size() == 2 - && curr.is_isolated() - && curr.has_unique_region_id() - && next.rings.size() == 2 - && next.is_isolated() - && next.has_unique_region_id() - && curr_id == next_id - && curr_id != incoming_region_id; - - if (! possible) - { - return false; - } - } - - return true; -} - -inline bool intersection_pattern_common_interior1(std::size_t& selected_rank, - std::vector const& aggregation) -{ - // Pattern: coming from exterior ring, encountering an isolated - // parallel interior ring, which should be skipped, and the first - // left (normally intersection takes first right) should be taken. - // Solves cases #case_133_multi - // and #case_recursive_boxes_49 - - std::size_t const n = aggregation.size(); - if (n < 4) - { - return false; - } - - sort_by_side::rank_with_rings const& incoming = aggregation.front(); - sort_by_side::rank_with_rings const& outgoing = aggregation.back(); - - bool const incoming_ok = - incoming.all_from() - && incoming.rings.size() == 1 - && incoming.has_only(operation_intersection); - - if (! incoming_ok) - { - return false; - } - - bool const outgoing_ok = - outgoing.all_to() - && outgoing.rings.size() == 1 - && outgoing.has_only(operation_intersection) - && outgoing.region_id() == incoming.region_id(); - - if (! outgoing_ok) - { - return false; - } - - if (check_pairs(aggregation, incoming.region_id(), 1, n - 2)) - { - selected_rank = n - 1; - return true; - } - return false; -} - -inline bool intersection_pattern_common_interior2(std::size_t& selected_rank, - std::vector const& aggregation) -{ - // Pattern: coming from two exterior rings, encountering two isolated - // equal interior rings - - // See (for example, for ii) #case_recursive_boxes_53: - - // INCOMING: - // Rank 0 {11[0] (s:0, m:0) i F rgn: 1 ISO} {13[1] (s:1, m:0) i F rgn: 1 ISO} - - // PAIR: - // Rank 1 {13[0] (s:0, r:1, m:0) i T rgn: 3 ISO ->16} {11[1] (s:1, r:5, m:0) i T rgn: 3 ISO ->16} - // Rank 2 {13[0] (s:0, r:1, m:0) i F rgn: 3 ISO} {11[1] (s:1, r:5, m:0) i F rgn: 3 ISO} - - // LEAVING (in the same direction, take last one) - // Rank 3 {11[0] (s:0, m:0) i T rgn: 1 ISO ->10} {13[1] (s:1, m:0) i T rgn: 1 ISO ->10} - - - std::size_t const n = aggregation.size(); - if (n < 4) - { - return false; - } - - sort_by_side::rank_with_rings const& incoming = aggregation.front(); - sort_by_side::rank_with_rings const& outgoing = aggregation.back(); - - bool const incoming_ok = - incoming.all_from() - && incoming.rings.size() == 2 - && incoming.has_unique_region_id(); - - if (! incoming_ok) - { - return false; - } - - bool const outgoing_ok = - outgoing.all_to() - && outgoing.rings.size() == 2 - && outgoing.has_unique_region_id() - && outgoing.region_id() == incoming.region_id(); - - if (! outgoing_ok) - { - return false; - } - - bool const operation_ok = - (incoming.has_only(operation_continue) && outgoing.has_only(operation_continue)) - || (incoming.has_only(operation_intersection) && outgoing.has_only(operation_intersection)); - - if (! operation_ok) - { - return false; - } - - // Check if pairs 1,2 (and possibly 3,4 and 5,6 etc) satisfy - if (check_pairs(aggregation, incoming.region_id(), 1, n - 2)) - { - selected_rank = n - 1; - return true; - } - return false; -} - -inline bool intersection_pattern_common_interior3(std::size_t& selected_rank, - std::vector const& aggregation) -{ - // Pattern: approaches colocated turn (exterior+interior) from two - // different directions, and both leaves in the same direction - - // See #case_136_multi: - // INCOMING: - //Rank 0 {10[0] (s:0, m:0) c F rgn: 1 ISO} - - // PAIR: - //Rank 1 {14[0] (s:0, r:0, m:0) i T rgn: 2 ISO ->16} {11[1] (s:1, r:1, m:0) i T rgn: 2 ISO ->16} - //Rank 2 {14[0] (s:0, r:0, m:0) i F rgn: 2 ISO} {11[1] (s:1, r:1, m:0) i F rgn: 2 ISO} - - // LEAVING (select this one): - //Rank 3 {10[0] (s:0, m:0) c T rgn: 1 ISO ->12} {10[1] (s:1, m:0) c T rgn: 1 ISO ->12} - - // ADDITIONALLY: (other polygon coming in) - //Rank 4 {10[1] (s:1, m:0) c F rgn: 1 ISO} - - std::size_t const n = aggregation.size(); - if (n < 4) - { - return false; - } - - sort_by_side::rank_with_rings const& incoming = aggregation.front(); - sort_by_side::rank_with_rings const& outgoing = aggregation[n - 2]; - sort_by_side::rank_with_rings const& last = aggregation.back(); - - bool const incoming_ok = - incoming.all_from() - && incoming.rings.size() == 1 - && incoming.has_only(operation_continue); - - if (! incoming_ok) - { - return false; - } - - bool const outgoing_ok = - outgoing.all_to() - && outgoing.rings.size() == 2 - && outgoing.has_only(operation_continue) - && outgoing.has_unique_region_id() - && outgoing.region_id() == incoming.region_id() - && last.all_from() - && last.rings.size() == 1 - && last.region_id() == incoming.region_id() - && last.all_from(); - - if (! outgoing_ok) - { - return false; - } - - // Check if pairs 1,2 (and possibly 3,4 and 5,6 etc) satisfy - if (check_pairs(aggregation, incoming.region_id(), 1, n - 3)) - { - selected_rank = n - 2; - return true; - } - return false; -} - - -inline bool intersection_pattern_common_interior4(std::size_t& selected_rank, - std::vector const& aggregation) -{ - // Pattern: approaches colocated turn (exterior+interior) from same - // direction, but leaves in two different directions - - // See #case_137_multi: - - // INCOMING: - //Rank 0 {11[0] (s:0, m:0) i F rgn: 1 ISO} {10[1] (s:1, m:0) i F rgn: 1 ISO} - - // PAIR: - //Rank 1 {13[0] (s:0, r:0, m:0) i T rgn: 2 ISO ->15} {11[1] (s:1, r:1, m:0) i T rgn: 2 ISO ->15} - //Rank 2 {13[0] (s:0, r:0, m:0) i F rgn: 2 ISO} {11[1] (s:1, r:1, m:0) i F rgn: 2 ISO} - - // LEAVING (in two different directions, take penultimate one) - //Rank 3 {10[1] (s:1, m:0) i T rgn: 1 ISO ->0} - //Rank 4 {11[0] (s:0, m:0) i T rgn: 1 ISO ->12} - - std::size_t const n = aggregation.size(); - if (n < 4) - { - return false; - } - - sort_by_side::rank_with_rings const& incoming = aggregation.front(); - sort_by_side::rank_with_rings const& extra = aggregation[n - 2]; - sort_by_side::rank_with_rings const& outgoing = aggregation.back(); - - bool const incoming_ok = - incoming.all_from() - && incoming.rings.size() == 2 - && incoming.has_unique_region_id() - && incoming.has_only(operation_intersection); - - if (! incoming_ok) - { - return false; - } - - bool const outgoing_ok = - outgoing.all_to() - && outgoing.rings.size() == 1 - && outgoing.has_only(operation_intersection) - && outgoing.region_id() == incoming.region_id() - && extra.all_to() - && extra.rings.size() == 1 - && extra.has_only(operation_intersection) - && extra.region_id() == incoming.region_id(); - - if (! outgoing_ok) - { - return false; - } - - // Check if pairs 1,2 (and possibly 3,4 and 5,6 etc) satisfy - if (check_pairs(aggregation, incoming.region_id(), 1, n - 3)) - { - selected_rank = n - 2; - return true; - } - return false; -} - -inline bool intersection_pattern_common_interior5(std::size_t& selected_rank, - std::vector const& aggregation) -{ - // Pattern: isolated regions - - // See #case_recursive_boxes_65 - - // INCOMING: - // Rank 0 {19[0] (s:0, r:2, m:0) i F rgn: 4 ISO} - - // Rank 1 {19[1] (s:1, m:0) i T rgn: 1 ISO FIN ->18 (2.5)} - // Rank 2 {21[1] (s:1, m:2) i F rgn: 1 ISO} - // Rank 3 {21[1] (s:1, m:2) i T rgn: 1 ISO ->17 (2)} - // Rank 4 {19[1] (s:1, m:0) i F rgn: 1 ISO FIN} - - // LEAVING (take this one): - // Rank 5 {19[0] (s:0, r:2, m:0) i T rgn: 4 ISO ->22 (1)} - - std::size_t const n = aggregation.size(); - if (n < 3) - { - return false; - } - - sort_by_side::rank_with_rings const& incoming = aggregation.front(); - sort_by_side::rank_with_rings const& outgoing = aggregation.back(); - - bool const incoming_ok = - incoming.all_from() - && incoming.has_unique_region_id() - && incoming.is_isolated(); - - if (! incoming_ok) - { - return false; - } - - signed_size_type const incoming_region_id = incoming.region_id(); - - bool const outgoing_ok = - outgoing.all_to() - && outgoing.has_unique_region_id() - && outgoing.is_isolated() - && outgoing.region_id() == incoming_region_id; - - if (! outgoing_ok) - { - return false; - } - - selected_rank = n - 1; - bool other_region = true; - - // Assumed is that other regions go (T) and come back (F) - for (std::size_t i = 1; i < n - 1; i++) - { - sort_by_side::rank_with_rings const& rwr = aggregation[i]; - if (! rwr.has_unique_region_id() || ! rwr.is_isolated()) - { - return false; - } - signed_size_type const region_id = rwr.region_id(); - if (other_region && region_id != incoming_region_id) - { - // OK - } - else if (other_region && region_id == incoming_region_id) - { - // OK, next phase (same region as incoming region) - selected_rank = i; - other_region = false; - } - else if (! other_region && region_id != incoming_region_id) - { - // After that the region is the same is incoming, it should - // stay like that - return false; - } - } - - return true; -} - -inline bool intersection_pattern_common_interior6(std::size_t& selected_rank, - std::vector const& aggregation) -{ - // Pattern: isolated regions in between - - // See #case_recursive_boxes_75 - - // Incoming: one region - // In between: several rings having isolated region, all the same - // Outging == incoming - - std::size_t const n = aggregation.size(); - if (n < 3) - { - return false; - } - - sort_by_side::rank_with_rings const& incoming = aggregation.front(); - sort_by_side::rank_with_rings const& outgoing = aggregation.back(); - sort_by_side::rank_with_rings const& first_isolated = aggregation[2]; - - bool const incoming_ok = - incoming.all_from() - && incoming.has_unique_region_id() - && ! incoming.is_isolated(); - - if (! incoming_ok) - { - return false; - } - - signed_size_type const incoming_region_id = incoming.region_id(); - - bool const outgoing_ok = - outgoing.all_to() - && outgoing.has_unique_region_id() - && ! outgoing.is_isolated() - && outgoing.region_id() == incoming_region_id; - - if (! outgoing_ok) - { - return false; - } - - const signed_size_type isolated_region_id = first_isolated.region_id(); - - for (std::size_t i = 1; i < n - 1; i++) - { - sort_by_side::rank_with_rings const& rwr = aggregation[i]; - if (! rwr.has_unique_region_id() - || ! rwr.is_isolated() - || rwr.region_id() != isolated_region_id) - { - return false; - } - } - - selected_rank = n - 1; - - return true; -} - -}} // namespace detail::overlay -#endif // DOXYGEN_NO_DETAIL - -}} // namespace boost::geometry - -#endif // BOOST_GEOMETRY_ALGORITHMS_DETAIL_OVERLAY_TRAVERSAL_INTERSECTION_PATTERNS_HPP diff --git a/test/algorithms/overlay/multi_overlay_cases.hpp b/test/algorithms/overlay/multi_overlay_cases.hpp index db3eb40d4..69d594637 100644 --- a/test/algorithms/overlay/multi_overlay_cases.hpp +++ b/test/algorithms/overlay/multi_overlay_cases.hpp @@ -1242,6 +1242,14 @@ static std::string case_recursive_boxes_81[2] = "MULTIPOLYGON(((2 4,2 2,1 2,0 1,0 3,1 3,1 4,2 4)),((2 4,2 5,3 4,2 4)),((3 4,5 4,5 3,3 3,3 4)),((1 4,0 4,0 5,1 5,1 4)),((2 1,2 0,0 0,0 1,2 1)),((4 2,5 2,4 1,3 1,4 2)),((4 1,5 1,4 0,4 1)))" }; +static std::string case_recursive_boxes_82[2] = +{ + // Contains two outgoing arcs on same ring causing current aggregation implementation to fail. + // Fixed by greatly simplifying the code, skipping aggregations and using sbs directly (which is now possible, now that isolation-information is much better) + "MULTIPOLYGON(((4 0,5 1,5 0,4 0)),((3 3,3 1,4 1,3 0,0 0,0 5,1 5,1 4,1.5 3.5,2 4,2 3,3 3),(2 2,2 1,3 2,2 2)),((2 4,3 5,4 5,3.5 4.5,5 3,3 3,3 4,2 4)),((4 4,4 5,5 5,4.5 4.5,5 4,4 4)))", + "MULTIPOLYGON(((2 4,2 5,4 5,4 4,2 4)),((2 4,2 3,5 3,5 2,4 2,4 1,1 1,1 2,0 2,0 5,1 5,1 4,2 4),(2 2,1 2,1.5 1.5,2 2),(3 2,3.5 1.5,4 2,3 2)),((4 4,5 5,5 4,4 4)))" +}; + static std::string pie_21_7_21_0_3[2] = { "MULTIPOLYGON(((2500 2500,2500 3875,2855 3828,3187 3690,3472 3472,3690 3187,3828 2855,3875 2500,3828 2144,3690 1812,3472 1527,3187 1309,2855 1171,2499 1125,2144 1171,1812 1309,1527 1527,1309 1812,1171 2144,1125 2499,1171 2855,1309 3187,2500 2500)))", diff --git a/test/algorithms/set_operations/difference/difference_multi.cpp b/test/algorithms/set_operations/difference/difference_multi.cpp index 313c8bb14..7da30ee61 100644 --- a/test/algorithms/set_operations/difference/difference_multi.cpp +++ b/test/algorithms/set_operations/difference/difference_multi.cpp @@ -448,12 +448,7 @@ void test_areal() sym_settings); } -#if defined(BOOST_GEOMETRY_INCLUDE_SELF_TURNS) && ! defined(BOOST_GEOMETRY_NO_ROBUSTNESS) TEST_DIFFERENCE(mysql_regression_1_65_2017_08_31, 1, 4.30697514e-7, 3, 152.0642, 4); -#else - // Misses one turn which is actually weird because there are no self-turns involved - TEST_DIFFERENCE(mysql_regression_1_65_2017_08_31, 0, 0, 3, 152.0642, 3); -#endif } diff --git a/test/algorithms/set_operations/intersection/intersection_multi.cpp b/test/algorithms/set_operations/intersection/intersection_multi.cpp index aa63d85fc..b48f36c81 100644 --- a/test/algorithms/set_operations/intersection/intersection_multi.cpp +++ b/test/algorithms/set_operations/intersection/intersection_multi.cpp @@ -356,6 +356,11 @@ void test_areal() TEST_INTERSECTION(case_recursive_boxes_79, 5, -1, 9.0); TEST_INTERSECTION(case_recursive_boxes_80, 1, -1, 0.25); TEST_INTERSECTION(case_recursive_boxes_81, 5, -1, 3.75); +#ifdef BOOST_GEOMETRY_INCLUDE_SELF_TURNS + TEST_INTERSECTION(case_recursive_boxes_82, 5, -1, 8.5); +#else + TEST_INTERSECTION_IGNORE(case_recursive_boxes_82, 3, -1, 8.5); +#endif test_one("ggl_list_20120915_h2_a", ggl_list_20120915_h2[0], ggl_list_20120915_h2[1],