From bf159328e5b545dcf9e0578bed90cdfcf86423b0 Mon Sep 17 00:00:00 2001 From: Barend Gehrels Date: Wed, 7 Jun 2017 15:20:35 +0200 Subject: [PATCH] [traverse] fix errors in isolation detection in switch detector by taking clusters into account --- .../overlay/traversal_switch_detector.hpp | 93 +++++++++++++++++-- 1 file changed, 83 insertions(+), 10 deletions(-) diff --git a/include/boost/geometry/algorithms/detail/overlay/traversal_switch_detector.hpp b/include/boost/geometry/algorithms/detail/overlay/traversal_switch_detector.hpp index b71bdbbeb..0b4f393ef 100644 --- a/include/boost/geometry/algorithms/detail/overlay/traversal_switch_detector.hpp +++ b/include/boost/geometry/algorithms/detail/overlay/traversal_switch_detector.hpp @@ -53,7 +53,8 @@ struct traversal_switch_detector typedef typename boost::range_value::type turn_type; typedef typename turn_type::turn_operation_type turn_operation_type; - // For convenience + // Per ring, first turns are collected (in turn_indices), and later + // a region_id is assigned struct merged_ring_properties { signed_size_type region_id; @@ -64,11 +65,26 @@ struct traversal_switch_detector {} }; + struct connection_properties + { + std::size_t count; + std::set cluster_indices; + connection_properties() + : count(0) + {} + }; + + typedef std::map connection_map; + + // Per region, a set of properties is maintained, including its connections + // to other regions struct region_properties { signed_size_type region_id; isolation_type isolated; - std::map connected_region_counts; + + // Maps from connected region_id to their properties + connection_map connected_region_counts; region_properties() : region_id(-1) @@ -76,8 +92,10 @@ struct traversal_switch_detector {} }; + // Keeps turn indices per ring typedef std::map merge_map; typedef std::map region_connection_map; + typedef std::set::const_iterator set_iterator; inline traversal_switch_detector(Geometry1 const& geometry1, Geometry2 const& geometry2, @@ -101,15 +119,47 @@ struct traversal_switch_detector return properties.isolated; } + bool all_colocated = true; + int unique_cluster_id = -1; + for (typename connection_map::const_iterator it = properties.connected_region_counts.begin(); + all_colocated && it != properties.connected_region_counts.end(); ++it) + { + connection_properties const& cprop = it->second; + if (cprop.cluster_indices.size() != 1) + { + // Either no cluster (non colocated point), or more clusters + all_colocated = false; + } + int const cluster_id = *cprop.cluster_indices.begin(); + if (cluster_id == -1) + { + all_colocated = false; + } + else if (unique_cluster_id == -1) + { + unique_cluster_id = cluster_id; + } + else if (unique_cluster_id != cluster_id) + { + all_colocated = false; + } + } + if (all_colocated) + { + return isolation_yes; + } + + // It is isolated if there is only one connection, or if there are more connections but all - // of them are isolated themselves + // of them are isolated themselves, or if there are more connections + // but they are all colocated std::size_t non_isolation_count = 0; bool child_not_isolated = false; - for (std::map::const_iterator it = properties.connected_region_counts.begin(); + for (typename connection_map::const_iterator it = properties.connected_region_counts.begin(); it != properties.connected_region_counts.end(); ++it) { signed_size_type const region_id = it->first; - std::size_t const count = it->second; + connection_properties const& cprop = it->second; if (region_id == parent_region_id) { @@ -121,7 +171,7 @@ struct traversal_switch_detector // Find one of its ancestors again, this is a ring. Not isolated. return isolation_no; } - if (count > 1) + if (cprop.count > 1) { return isolation_no; } @@ -216,9 +266,32 @@ struct traversal_switch_detector // Force insertion m_connected_regions[id0].region_id = id0; m_connected_regions[id1].region_id = id1; - // Add reference to connection - m_connected_regions[id0].connected_region_counts[id1]++; - m_connected_regions[id1].connected_region_counts[id0]++; + + connection_properties& prop0 = m_connected_regions[id0].connected_region_counts[id1]; + connection_properties& prop1 = m_connected_regions[id1].connected_region_counts[id0]; + + if (turn.cluster_id < 0) + { + // Turn is not colocated, add reference to connection + prop0.count++; + prop1.count++; + } + else + { + // Turn is colocated, only add region reference if it was not yet registered + if (prop0.cluster_indices.count(turn.cluster_id) == 0) + { + prop0.count++; + } + if (prop1.cluster_indices.count(turn.cluster_id) == 0) + { + prop1.count++; + } + } + // Insert cluster-id (also -1 is inserted - reinsertion of + // same cluster id is OK) + prop0.cluster_indices.insert(turn.cluster_id); + prop1.cluster_indices.insert(turn.cluster_id); } } } @@ -256,7 +329,7 @@ struct traversal_switch_detector } cluster_info const& cinfo = it->second; - for (std::set::const_iterator sit = cinfo.turn_indices.begin(); + for (set_iterator sit = cinfo.turn_indices.begin(); sit != cinfo.turn_indices.end(); ++sit) { turn_type const& cluster_turn = m_turns[*sit];