Skip to content

Commit

Permalink
fix: set turns in closed clusters as non traversable
Browse files Browse the repository at this point in the history
  • Loading branch information
barendgehrels committed Feb 25, 2024
1 parent 16a7423 commit 142d505
Show file tree
Hide file tree
Showing 10 changed files with 351 additions and 77 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -973,8 +973,9 @@ inline void buffer_inserter(GeometryInput const& geometry_input, OutputIterator
{
collection.check_turn_in_original();
}

collection.verify_turns();
collection.handle_colocations();
collection.check_turn_in_pieces();
collection.make_traversable_consistent_per_cluster();

// Visit the piece collection. This does nothing (by default), but
// optionally a debugging tool can be attached (e.g. console or svg),
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -249,7 +249,8 @@ struct buffered_piece_collection

// Offsetted rings, and representations of original ring(s)
// both indexed by multi_index
buffered_ring_collection<buffered_ring<Ring> > offsetted_rings;
using ring_collection_t = buffered_ring_collection<buffered_ring<Ring>>;
ring_collection_t offsetted_rings;
std::vector<original_ring> original_rings;
std::vector<point_type> m_linear_end_points;

Expand Down Expand Up @@ -305,29 +306,6 @@ struct buffered_piece_collection
}
}

inline void verify_turns()
{
typedef detail::overlay::indexed_turn_operation
<
buffer_turn_operation_type
> indexed_turn_operation;
typedef std::map
<
ring_identifier,
std::vector<indexed_turn_operation>
> mapped_vector_type;
mapped_vector_type mapped_vector;

detail::overlay::create_map(m_turns, mapped_vector,
enriched_map_buffer_include_policy());

// Sort turns over offsetted ring(s)
for (auto& pair : mapped_vector)
{
std::sort(pair.second.begin(), pair.second.end(), buffer_less());
}
}

inline void deflate_check_turns()
{
if (! m_has_deflated)
Expand Down Expand Up @@ -470,24 +448,25 @@ struct buffered_piece_collection
}

update_turn_administration();
}

{
// Check if turns are inside pieces
turn_in_piece_visitor
<
typename geometry::cs_tag<point_type>::type,
turn_vector_type, piece_vector_type, DistanceStrategy, Strategy
> visitor(m_turns, m_pieces, m_distance_strategy, m_strategy);
inline void check_turn_in_pieces()
{
// Check if turns are inside pieces
turn_in_piece_visitor
<
typename geometry::cs_tag<point_type>::type,
turn_vector_type, piece_vector_type, DistanceStrategy, Strategy
> visitor(m_turns, m_pieces, m_distance_strategy, m_strategy);

geometry::partition
<
box_type
>::apply(m_turns, m_pieces, visitor,
turn_get_box<Strategy>(m_strategy),
turn_overlaps_box<Strategy>(m_strategy),
piece_get_box<Strategy>(m_strategy),
piece_overlaps_box<Strategy>(m_strategy));
}
geometry::partition
<
box_type
>::apply(m_turns, m_pieces, visitor,
turn_get_box<Strategy>(m_strategy),
turn_overlaps_box<Strategy>(m_strategy),
piece_get_box<Strategy>(m_strategy),
piece_overlaps_box<Strategy>(m_strategy));
}

inline void start_new_ring(bool deflate)
Expand Down Expand Up @@ -898,6 +877,61 @@ struct buffered_piece_collection

//-------------------------------------------------------------------------

inline void handle_colocations()
{
if (! detail::overlay::handle_colocations
<
false, false, overlay_buffer,
ring_collection_t, ring_collection_t
>(m_turns, m_clusters, m_robust_policy))
{
return;
}

detail::overlay::gather_cluster_properties
<
false, false, overlay_buffer
>(m_clusters, m_turns, detail::overlay::operation_union,
offsetted_rings, offsetted_rings, m_strategy);

for (const auto& cluster : m_clusters)
{
if (cluster.second.open_count == 0 && cluster.second.spike_count == 0)
{
// If the cluster is completely closed, mark it as not traversable.
for (auto index : cluster.second.turn_indices)
{
m_turns[index].is_turn_traversable = false;
}
}
}
}

inline void make_traversable_consistent_per_cluster()
{
for (auto const& cluster : m_clusters)
{
bool is_traversable = false;
for (auto index : cluster.second.turn_indices)
{
if (m_turns[index].is_turn_traversable)
{
// If there is one turn traversable in the cluster,
// then all turns should be traversable.
is_traversable = true;
break;
}
}
if (is_traversable)
{
for (auto index : cluster.second.turn_indices)
{
m_turns[index].is_turn_traversable = true;
}
}
}
}

inline void enrich()
{
enrich_intersection_points<false, false, overlay_buffer>(m_turns,
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -27,11 +27,11 @@ struct cluster_info
std::set<signed_size_type> turn_indices;

//! Number of open spaces (e.g. 2 for touch)
std::size_t open_count;
std::size_t open_count{0};

inline cluster_info()
: open_count(0)
{}
//! Number of spikes, where a segment goes to the cluster point
//! and leaves immediately in the opposite direction.
std::size_t spike_count{0};
};


Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -137,6 +137,13 @@ inline void discard_duplicate_start_turns(Turns& turns,
{
for (std::size_t const& i : it->second)
{
if (turns[i].cluster_id != turn.cluster_id)
{
// The turns are not part of the same cluster,
// or one is clustered and the other is not.
// This is not corresponding.
continue;
}
if (corresponding_turn(turn, turns[i],
geometry0, geometry1))
{
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -383,6 +383,7 @@ inline void enrich_intersection_points(Turns& turns,
? detail::overlay::operation_intersection
: detail::overlay::operation_union;
constexpr bool is_dissolve = OverlayType == overlay_dissolve;
constexpr bool is_buffer = OverlayType == overlay_buffer;

using turn_type = typename boost::range_value<Turns>::type;
using indexed_turn_operation = detail::overlay::indexed_turn_operation
Expand All @@ -396,16 +397,36 @@ inline void enrich_intersection_points(Turns& turns,
std::vector<indexed_turn_operation>
>;

// From here on, turn indexes are used (in clusters, next_index, etc)
// and turns may not be DELETED - they may only be flagged as discarded
// Turns are often used by index (in clusters, next_index, etc)
// and turns may therefore NOT be DELETED - they may only be flagged as discarded

discard_duplicate_start_turns(turns, geometry1, geometry2);

bool has_cc = false;
bool const has_colocations
= detail::overlay::handle_colocations
bool has_colocations = false;

if (BOOST_GEOMETRY_CONDITION (! is_buffer))
{
// Handle colocations, gathering clusters and (below) their properties.
has_colocations = detail::overlay::handle_colocations
<
Reverse1, Reverse2, OverlayType, Geometry1, Geometry2
>(turns, clusters, robust_policy);
// Gather cluster properties (using even clusters with
// discarded turns - for open turns)
detail::overlay::gather_cluster_properties
<
Reverse1, Reverse2, OverlayType, Geometry1, Geometry2
>(turns, clusters, robust_policy);
Reverse1,
Reverse2,
OverlayType
>(clusters, turns, target_operation,
geometry1, geometry2, strategy);
}
else
{
// For buffer, this was already done before calling enrich_intersection_points.
has_colocations = ! clusters.empty();
}

// Discard turns not part of target overlay
for (auto& turn : turns)
Expand Down Expand Up @@ -479,17 +500,8 @@ inline void enrich_intersection_points(Turns& turns,

if (has_colocations)
{
// First gather cluster properties (using even clusters with
// discarded turns - for open turns), then clean up clusters
detail::overlay::gather_cluster_properties
<
Reverse1,
Reverse2,
OverlayType
>(clusters, turns, target_operation,
geometry1, geometry2, strategy);

detail::overlay::cleanup_clusters(turns, clusters);
detail::overlay::colocate_clusters(clusters, turns);
}

// After cleaning up clusters assign the next turns
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -97,7 +97,6 @@ inline void cleanup_clusters(Turns& turns, Clusters& clusters)
}

remove_clusters(turns, clusters);
colocate_clusters(clusters, turns);
}

template <typename Turn, typename IndexSet>
Expand Down Expand Up @@ -357,7 +356,7 @@ inline bool handle_colocations(Turns& turns, Clusters& clusters,
{
std::cout << kv.first << std::endl;
for (auto const& toi : kv.second)
{
{
detail::debug::debug_print_turn(turns[toi.turn_index]);
std::cout << std::endl;
}
Expand Down Expand Up @@ -463,6 +462,21 @@ inline void gather_cluster_properties(Clusters& clusters, Turns& turns,

cinfo.open_count = sbs.open_count(for_operation);

// Determine spikes
cinfo.spike_count = 0;
for (std::size_t i = 0; i + 1 < sbs.m_ranked_points.size(); i++)
{
auto const& current = sbs.m_ranked_points[i];
auto const& next = sbs.m_ranked_points[i + 1];
if (current.rank == next.rank
&& current.direction == detail::overlay::sort_by_side::dir_from
&& next.direction == detail::overlay::sort_by_side::dir_to)
{
// It leaves, from cluster point, and immediately returns.
cinfo.spike_count += 1;
}
}

bool const set_startable = OverlayType != overlay_dissolve;

// Unset the startable flag for all 'closed' zones. This does not
Expand All @@ -475,7 +489,8 @@ inline void gather_cluster_properties(Clusters& clusters, Turns& turns,
turn_operation_type& op = turn.operations[ranked.operation_index];

if (set_startable
&& for_operation == operation_union && cinfo.open_count == 0)
&& for_operation == operation_union
&& cinfo.open_count == 0)
{
op.enriched.startable = false;
}
Expand Down
41 changes: 31 additions & 10 deletions include/boost/geometry/algorithms/detail/overlay/traversal.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -561,7 +561,7 @@ public :

inline int priority_of_turn_in_cluster_union(sort_by_side::rank_type selected_rank,
typename sbs_type::rp const& ranked_point,
std::set<signed_size_type> const& cluster_indices,
cluster_info const& cinfo,
signed_size_type start_turn_index, int start_op_index) const
{
// Returns 0: not OK
Expand Down Expand Up @@ -589,19 +589,22 @@ public :
{
// Check counts: in some cases interior rings might be generated with
// polygons on both sides. For dissolve it can be anything.
return 0;

// If this forms a spike, going to/from the cluster point in the same
// (opposite) direction, it can still be used.
return cinfo.spike_count > 0 ? 1 : 0;
}

bool const to_start = ranked_point.turn_index == start_turn_index;
bool const to_start_index = ranked_point.operation_index == start_op_index;

bool const next_in_same_cluster
= cluster_indices.count(op.enriched.get_next_turn_index()) > 0;
= cinfo.turn_indices.count(op.enriched.get_next_turn_index()) > 0;

return to_start && to_start_index ? 4
: to_start ? 3
: next_in_same_cluster ? 1
: 2
return to_start && to_start_index ? 5
: to_start ? 4
: next_in_same_cluster ? 2
: 3
;
}

Expand Down Expand Up @@ -647,7 +650,7 @@ public :
}

inline bool select_from_cluster_union(signed_size_type& turn_index,
std::set<signed_size_type> const& cluster_indices,
cluster_info const& cinfo,
int& op_index, sbs_type const& sbs,
signed_size_type start_turn_index, int start_op_index) const
{
Expand All @@ -664,7 +667,7 @@ public :
}

int const priority = priority_of_turn_in_cluster_union(selected_rank,
ranked_point, cluster_indices, start_turn_index, start_op_index);
ranked_point, cinfo, start_turn_index, start_op_index);

if (priority > current_priority)
{
Expand Down Expand Up @@ -791,6 +794,24 @@ public :
return false;
}

if (is_union && cinfo.open_count == 0 && cinfo.spike_count > 0)
{
// Leave the cluster from the spike.
for (std::size_t i = 0; i + 1 < sbs.m_ranked_points.size(); i++)
{
auto const& current = sbs.m_ranked_points[i];
auto const& next = sbs.m_ranked_points[i + 1];
if (current.rank == next.rank
&& current.direction == detail::overlay::sort_by_side::dir_from
&& next.direction == detail::overlay::sort_by_side::dir_to)
{
turn_index = next.turn_index;
op_index = next.operation_index;
return true;
}
}
}

cluster_exits<OverlayType, Turns, sbs_type> exits(m_turns, cinfo.turn_indices, sbs);

if (exits.apply(turn_index, op_index))
Expand All @@ -802,7 +823,7 @@ public :

if (is_union)
{
result = select_from_cluster_union(turn_index, cinfo.turn_indices,
result = select_from_cluster_union(turn_index, cinfo,
op_index, sbs,
start_turn_index, start_op_index);
if (! result)
Expand Down
Loading

0 comments on commit 142d505

Please sign in to comment.