Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

feat: major rewrite of traversal #1369

Open
wants to merge 1 commit into
base: develop
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
3 changes: 2 additions & 1 deletion CMakeLists.txt
Original file line number Diff line number Diff line change
Expand Up @@ -26,6 +26,7 @@ target_link_libraries(boost_geometry
Boost::core
Boost::crc
Boost::function_types
Boost::graph
Boost::iterator
Boost::lexical_cast
Boost::math
Expand Down Expand Up @@ -103,6 +104,7 @@ if(BUILD_TESTING AND EXISTS "${CMAKE_CURRENT_SOURCE_DIR}/test/CMakeLists.txt")
algorithm
any
crc
graph
lexical_cast
math
multiprecision
Expand Down Expand Up @@ -131,4 +133,3 @@ if(BUILD_TESTING AND EXISTS "${CMAKE_CURRENT_SOURCE_DIR}/test/CMakeLists.txt")
add_subdirectory(index/test EXCLUDE_FROM_ALL)

endif()

Original file line number Diff line number Diff line change
Expand Up @@ -363,6 +363,11 @@ struct visit_pieces_default_policy
template <typename Collection>
static inline void apply(Collection const&, int)
{}

template <typename Turns, typename Cluster, typename Connections>
inline void visit_cluster_connections(signed_size_type cluster_id,
Turns const& turns, Cluster const& cluster, Connections const& connections) {}

};

template
Expand Down Expand Up @@ -940,6 +945,7 @@ inline void buffer_inserter(GeometryInput const& geometry_input, OutputIterator
}
collection.handle_colocations();
collection.check_turn_in_pieces();
collection.assign_side_counts(visit_pieces_policy);
collection.make_traversable_consistent_per_cluster();

// Visit the piece collection. This does nothing (by default), but
Expand All @@ -949,7 +955,7 @@ inline void buffer_inserter(GeometryInput const& geometry_input, OutputIterator
visit_pieces_policy.apply(const_collection, 0);

collection.discard_rings();
collection.block_turns();
collection.discard_non_traversable_turns();
collection.enrich();

// phase 1: turns (after enrichment/clustering)
Expand All @@ -960,7 +966,7 @@ inline void buffer_inserter(GeometryInput const& geometry_input, OutputIterator
collection.deflate_check_turns();
}

collection.traverse();
collection.traverse(visit_pieces_policy);

// Reverse all offsetted rings / traversed rings if:
// - they were generated on the negative side (deflate) of polygons
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -21,7 +21,8 @@
#include <boost/geometry/core/coordinate_type.hpp>
#include <boost/geometry/core/point_type.hpp>

#include <boost/geometry/algorithms/detail/overlay/backtrack_check_si.hpp>
#include <boost/geometry/algorithms/disjoint.hpp>
#include <boost/geometry/algorithms/expand.hpp>
#include <boost/geometry/algorithms/detail/overlay/traversal_info.hpp>
#include <boost/geometry/algorithms/detail/overlay/turn_info.hpp>

Expand All @@ -36,54 +37,6 @@ namespace boost { namespace geometry
namespace detail { namespace buffer
{

class backtrack_for_buffer
{
public :
using state_type = detail::overlay::backtrack_state;

template
<
typename Operation,
typename Rings,
typename Turns,
typename Geometry,
typename Strategy,
typename Visitor
>
static inline void apply(std::size_t size_at_start,
Rings& rings, typename boost::range_value<Rings>::type& ring,
Turns& turns,
typename boost::range_value<Turns>::type const& /*turn*/,
Operation& operation,
detail::overlay::traverse_error_type /*traverse_error*/,
Geometry const& ,
Geometry const& ,
Strategy const& ,
state_type& state,
Visitor& /*visitor*/
)
{
#if defined(BOOST_GEOMETRY_COUNT_BACKTRACK_WARNINGS)
extern int g_backtrack_warning_count;
g_backtrack_warning_count++;
#endif
//std::cout << "!";
//std::cout << "WARNING " << traverse_error_string(traverse_error) << std::endl;

state.m_good = false;

// Make bad output clean
rings.resize(size_at_start);
ring.clear();

// Reject this as a starting point
operation.visited.set_rejected();

// And clear all visit info
clear_visit_info(turns);
}
};

struct buffer_overlay_visitor
{
public :
Expand All @@ -98,11 +51,6 @@ public :
{
}

template <typename Turns, typename Turn, typename Operation>
void visit_traverse_reject(Turns const& , Turn const& , Operation const& ,
detail::overlay::traverse_error_type )
{}

template <typename Rings>
void visit_generated_rings(Rings const& )
{}
Expand Down Expand Up @@ -141,15 +89,13 @@ struct buffer_turn_info
// Information if turn can be used. It is not traversable if it is within
// another piece, or within the original (depending on deflation),
// or (for deflate) if there are not enough points to traverse it.
bool is_turn_traversable;

bool is_linear_end_point;
bool within_original;
signed_size_type count_in_original; // increased by +1 for in ext.ring, -1 for int.ring

inline buffer_turn_info()
: turn_index(0)
, is_turn_traversable(true)
, is_linear_end_point(false)
, within_original(false)
, count_in_original(0)
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -37,9 +37,12 @@

#include <boost/geometry/geometries/ring.hpp>

#include <boost/geometry/algorithms/detail/overlay/graph/assign_side_counts.hpp>
#include <boost/geometry/algorithms/detail/buffer/buffered_ring.hpp>
#include <boost/geometry/algorithms/detail/buffer/buffer_policies.hpp>
#include <boost/geometry/algorithms/detail/overlay/cluster_info.hpp>
#include <boost/geometry/algorithms/detail/overlay/get_properties_ahead.hpp>
#include <boost/geometry/algorithms/detail/overlay/handle_colocations.hpp>
#include <boost/geometry/algorithms/detail/buffer/get_piece_turns.hpp>
#include <boost/geometry/algorithms/detail/buffer/piece_border.hpp>
#include <boost/geometry/algorithms/detail/buffer/turn_in_piece_visitor.hpp>
Expand Down Expand Up @@ -308,7 +311,7 @@ struct buffered_piece_collection
// be three turns (which cannot be checked here - TODO: add to traverse)
for (auto& turn : m_turns)
{
if (! turn.is_turn_traversable)
if (! turn.is_traversable)
{
continue;
}
Expand Down Expand Up @@ -348,18 +351,18 @@ struct buffered_piece_collection

for (auto& turn : m_turns)
{
if (turn.is_turn_traversable)
if (turn.is_traversable)
{
if (deflate && turn.count_in_original <= 0)
{
// For deflate/negative buffers:
// it is not in the original, so don't use it
turn.is_turn_traversable = false;
turn.is_traversable = false;
}
else if (! deflate && turn.count_in_original > 0)
{
// For inflate: it is in original, so don't use it
turn.is_turn_traversable = false;
turn.is_traversable = false;
}
}
}
Expand Down Expand Up @@ -439,6 +442,21 @@ struct buffered_piece_collection
detail::section::overlaps_section_box<Strategy>(m_strategy));
}

// This fixes the fact that sometimes wrong ix or xi turns are generated.
// See comments in get_turn_info (block_q).
// The ix turns are not relevant for buffer anyway, it is fine to remove them,
// as long as they are removed before calculating turn indices.
// It will also enhance performance a bit (no need to calculate point in original,
// point in piece). Therefore we remove ii and xx as well.
m_turns.erase(std::remove_if(m_turns.begin(), m_turns.end(),
[](auto const& turn)
{
bool const is_ix = turn.combination(overlay::operation_intersection, overlay::operation_blocked);
bool const is_ii = turn.both(overlay::operation_intersection);
return is_ix || is_ii || turn.blocked();
}),
m_turns.end());

update_turn_administration();
}

Expand Down Expand Up @@ -869,29 +887,27 @@ 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))
{
return;
}

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

template <typename Visitor>
inline void assign_side_counts(Visitor& visitor)
{
// Assign count_left, count_right and open_count
detail::overlay::assign_side_counts
<false, false, overlay_buffer>
(offsetted_rings, offsetted_rings,
m_turns, m_clusters,
m_strategy, visitor);

// Mark closed clusters as not traversable
for (auto const& cluster : m_clusters)
{
if (cluster.second.open_count == 0 && cluster.second.spike_count == 0)
if (cluster.second.open_count == 0)
{
// If the cluster is completely closed, mark it as not traversable.
for (auto const& index : cluster.second.turn_indices)
{
m_turns[index].is_turn_traversable = false;
m_turns[index].is_traversable = false;
}
}
}
Expand All @@ -904,7 +920,7 @@ struct buffered_piece_collection
bool is_traversable = false;
for (auto const& index : cluster.second.turn_indices)
{
if (m_turns[index].is_turn_traversable)
if (m_turns[index].is_traversable)
{
// If there is one turn traversable in the cluster,
// then all turns should be traversable.
Expand All @@ -916,17 +932,21 @@ struct buffered_piece_collection
{
for (auto const& index : cluster.second.turn_indices)
{
m_turns[index].is_turn_traversable = true;
m_turns[index].is_traversable = true;
}
}
}
}

inline void enrich()
{
enrich_intersection_points<false, false, overlay_buffer>(m_turns,
m_clusters, offsetted_rings, offsetted_rings,
m_strategy);
detail::overlay::enrich_discard_turns<overlay_buffer>(
m_turns, m_clusters, offsetted_rings, offsetted_rings, m_strategy);
detail::overlay::enrich_turns<false, false, overlay_buffer>(
m_turns, offsetted_rings, offsetted_rings, m_strategy);

detail::overlay::get_properties_ahead<false, false>(m_turns, m_clusters, offsetted_rings,
offsetted_rings, m_strategy);
}

// Discards all rings which do have not-OK intersection points only.
Expand All @@ -935,7 +955,7 @@ struct buffered_piece_collection
{
for (auto const& turn : m_turns)
{
if (turn.is_turn_traversable)
if (turn.is_traversable)
{
offsetted_rings[turn.operations[0].seg_id.multi_index].has_accepted_intersections = true;
offsetted_rings[turn.operations[1].seg_id.multi_index].has_accepted_intersections = true;
Expand Down Expand Up @@ -1013,28 +1033,27 @@ struct buffered_piece_collection
}
}

inline void block_turns()
inline void discard_non_traversable_turns()
{
for (auto& turn : m_turns)
{
if (! turn.is_turn_traversable)
if (! turn.is_traversable)
{
// Discard this turn (don't set it to blocked to avoid colocated
// clusters being discarded afterwards
// Discard the non traversable turn
turn.discarded = true;
}
}
}

inline void traverse()
template <typename PieceVisitor>
inline void traverse(PieceVisitor const& piece_visitor)
{
using traverser = detail::overlay::traverse
<
false, false,
buffered_ring_collection<buffered_ring<Ring> >,
buffered_ring_collection<buffered_ring<Ring > >,
overlay_buffer,
backtrack_for_buffer
overlay_buffer
>;
std::map<ring_identifier, overlay::ring_turn_info> turn_info_per_ring;

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -75,7 +75,7 @@ struct include_turn_policy
template <typename Turn>
static inline bool apply(Turn const& turn)
{
return turn.is_turn_traversable;
return turn.is_traversable;
}
};

Expand All @@ -89,7 +89,7 @@ struct turn_in_original_overlaps_box
template <typename Box, typename Turn>
inline bool apply(Box const& box, Turn const& turn) const
{
if (! turn.is_turn_traversable || turn.within_original)
if (! turn.is_traversable || turn.within_original)
{
// Skip all points already processed
return false;
Expand Down Expand Up @@ -237,7 +237,7 @@ class turn_in_original_visitor
return true;
}

if (! turn.is_turn_traversable || turn.within_original)
if (! turn.is_traversable || turn.within_original)
{
// Skip all points already processed
return true;
Expand All @@ -262,7 +262,7 @@ class turn_in_original_visitor
if (code == 0)
{
// On border of original: always discard
mutable_turn.is_turn_traversable = false;
mutable_turn.is_traversable = false;
}

// Point is inside an original ring
Expand Down
Loading