Skip to content

Commit 494bbd6

Browse files
committed
feat: major rewrite of traversal
1 parent eeeb75a commit 494bbd6

File tree

85 files changed

+3992
-6772
lines changed

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

85 files changed

+3992
-6772
lines changed

CMakeLists.txt

+2-1
Original file line numberDiff line numberDiff line change
@@ -26,6 +26,7 @@ target_link_libraries(boost_geometry
2626
Boost::core
2727
Boost::crc
2828
Boost::function_types
29+
Boost::graph
2930
Boost::iterator
3031
Boost::lexical_cast
3132
Boost::math
@@ -103,6 +104,7 @@ if(BUILD_TESTING AND EXISTS "${CMAKE_CURRENT_SOURCE_DIR}/test/CMakeLists.txt")
103104
algorithm
104105
any
105106
crc
107+
graph
106108
lexical_cast
107109
math
108110
multiprecision
@@ -131,4 +133,3 @@ if(BUILD_TESTING AND EXISTS "${CMAKE_CURRENT_SOURCE_DIR}/test/CMakeLists.txt")
131133
add_subdirectory(index/test EXCLUDE_FROM_ALL)
132134

133135
endif()
134-

include/boost/geometry/algorithms/detail/buffer/buffer_inserter.hpp

+8-2
Original file line numberDiff line numberDiff line change
@@ -363,6 +363,11 @@ struct visit_pieces_default_policy
363363
template <typename Collection>
364364
static inline void apply(Collection const&, int)
365365
{}
366+
367+
template <typename Turns, typename Cluster, typename Connections>
368+
inline void visit_cluster_connections(signed_size_type cluster_id,
369+
Turns const& turns, Cluster const& cluster, Connections const& connections) {}
370+
366371
};
367372

368373
template
@@ -940,6 +945,7 @@ inline void buffer_inserter(GeometryInput const& geometry_input, OutputIterator
940945
}
941946
collection.handle_colocations();
942947
collection.check_turn_in_pieces();
948+
collection.assign_side_counts(visit_pieces_policy);
943949
collection.make_traversable_consistent_per_cluster();
944950

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

951957
collection.discard_rings();
952-
collection.block_turns();
958+
collection.discard_non_traversable_turns();
953959
collection.enrich();
954960

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

963-
collection.traverse();
969+
collection.traverse(visit_pieces_policy);
964970

965971
// Reverse all offsetted rings / traversed rings if:
966972
// - they were generated on the negative side (deflate) of polygons

include/boost/geometry/algorithms/detail/buffer/buffer_policies.hpp

+2-56
Original file line numberDiff line numberDiff line change
@@ -21,7 +21,8 @@
2121
#include <boost/geometry/core/coordinate_type.hpp>
2222
#include <boost/geometry/core/point_type.hpp>
2323

24-
#include <boost/geometry/algorithms/detail/overlay/backtrack_check_si.hpp>
24+
#include <boost/geometry/algorithms/disjoint.hpp>
25+
#include <boost/geometry/algorithms/expand.hpp>
2526
#include <boost/geometry/algorithms/detail/overlay/traversal_info.hpp>
2627
#include <boost/geometry/algorithms/detail/overlay/turn_info.hpp>
2728

@@ -36,54 +37,6 @@ namespace boost { namespace geometry
3637
namespace detail { namespace buffer
3738
{
3839

39-
class backtrack_for_buffer
40-
{
41-
public :
42-
using state_type = detail::overlay::backtrack_state;
43-
44-
template
45-
<
46-
typename Operation,
47-
typename Rings,
48-
typename Turns,
49-
typename Geometry,
50-
typename Strategy,
51-
typename Visitor
52-
>
53-
static inline void apply(std::size_t size_at_start,
54-
Rings& rings, typename boost::range_value<Rings>::type& ring,
55-
Turns& turns,
56-
typename boost::range_value<Turns>::type const& /*turn*/,
57-
Operation& operation,
58-
detail::overlay::traverse_error_type /*traverse_error*/,
59-
Geometry const& ,
60-
Geometry const& ,
61-
Strategy const& ,
62-
state_type& state,
63-
Visitor& /*visitor*/
64-
)
65-
{
66-
#if defined(BOOST_GEOMETRY_COUNT_BACKTRACK_WARNINGS)
67-
extern int g_backtrack_warning_count;
68-
g_backtrack_warning_count++;
69-
#endif
70-
//std::cout << "!";
71-
//std::cout << "WARNING " << traverse_error_string(traverse_error) << std::endl;
72-
73-
state.m_good = false;
74-
75-
// Make bad output clean
76-
rings.resize(size_at_start);
77-
ring.clear();
78-
79-
// Reject this as a starting point
80-
operation.visited.set_rejected();
81-
82-
// And clear all visit info
83-
clear_visit_info(turns);
84-
}
85-
};
86-
8740
struct buffer_overlay_visitor
8841
{
8942
public :
@@ -98,11 +51,6 @@ public :
9851
{
9952
}
10053

101-
template <typename Turns, typename Turn, typename Operation>
102-
void visit_traverse_reject(Turns const& , Turn const& , Operation const& ,
103-
detail::overlay::traverse_error_type )
104-
{}
105-
10654
template <typename Rings>
10755
void visit_generated_rings(Rings const& )
10856
{}
@@ -141,15 +89,13 @@ struct buffer_turn_info
14189
// Information if turn can be used. It is not traversable if it is within
14290
// another piece, or within the original (depending on deflation),
14391
// or (for deflate) if there are not enough points to traverse it.
144-
bool is_turn_traversable;
14592

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

15097
inline buffer_turn_info()
15198
: turn_index(0)
152-
, is_turn_traversable(true)
15399
, is_linear_end_point(false)
154100
, within_original(false)
155101
, count_in_original(0)

include/boost/geometry/algorithms/detail/buffer/buffered_piece_collection.hpp

+53-34
Original file line numberDiff line numberDiff line change
@@ -37,9 +37,12 @@
3737

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

40+
#include <boost/geometry/algorithms/detail/overlay/graph/assign_side_counts.hpp>
4041
#include <boost/geometry/algorithms/detail/buffer/buffered_ring.hpp>
4142
#include <boost/geometry/algorithms/detail/buffer/buffer_policies.hpp>
4243
#include <boost/geometry/algorithms/detail/overlay/cluster_info.hpp>
44+
#include <boost/geometry/algorithms/detail/overlay/get_properties_ahead.hpp>
45+
#include <boost/geometry/algorithms/detail/overlay/handle_colocations.hpp>
4346
#include <boost/geometry/algorithms/detail/buffer/get_piece_turns.hpp>
4447
#include <boost/geometry/algorithms/detail/buffer/piece_border.hpp>
4548
#include <boost/geometry/algorithms/detail/buffer/turn_in_piece_visitor.hpp>
@@ -308,7 +311,7 @@ struct buffered_piece_collection
308311
// be three turns (which cannot be checked here - TODO: add to traverse)
309312
for (auto& turn : m_turns)
310313
{
311-
if (! turn.is_turn_traversable)
314+
if (! turn.is_traversable)
312315
{
313316
continue;
314317
}
@@ -348,18 +351,18 @@ struct buffered_piece_collection
348351

349352
for (auto& turn : m_turns)
350353
{
351-
if (turn.is_turn_traversable)
354+
if (turn.is_traversable)
352355
{
353356
if (deflate && turn.count_in_original <= 0)
354357
{
355358
// For deflate/negative buffers:
356359
// it is not in the original, so don't use it
357-
turn.is_turn_traversable = false;
360+
turn.is_traversable = false;
358361
}
359362
else if (! deflate && turn.count_in_original > 0)
360363
{
361364
// For inflate: it is in original, so don't use it
362-
turn.is_turn_traversable = false;
365+
turn.is_traversable = false;
363366
}
364367
}
365368
}
@@ -439,6 +442,21 @@ struct buffered_piece_collection
439442
detail::section::overlaps_section_box<Strategy>(m_strategy));
440443
}
441444

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

@@ -869,29 +887,27 @@ struct buffered_piece_collection
869887

870888
inline void handle_colocations()
871889
{
872-
if (! detail::overlay::handle_colocations
873-
<
874-
false, false, overlay_buffer,
875-
ring_collection_t, ring_collection_t
876-
>(m_turns, m_clusters))
877-
{
878-
return;
879-
}
880-
881-
detail::overlay::gather_cluster_properties
882-
<
883-
false, false, overlay_buffer
884-
>(m_clusters, m_turns, detail::overlay::operation_union,
885-
offsetted_rings, offsetted_rings, m_strategy);
890+
detail::overlay::handle_colocations(m_turns, m_clusters);
891+
}
886892

893+
template <typename Visitor>
894+
inline void assign_side_counts(Visitor& visitor)
895+
{
896+
// Assign count_left, count_right and open_count
897+
detail::overlay::assign_side_counts
898+
<false, false, overlay_buffer>
899+
(offsetted_rings, offsetted_rings,
900+
m_turns, m_clusters,
901+
m_strategy, visitor);
902+
903+
// Mark closed clusters as not traversable
887904
for (auto const& cluster : m_clusters)
888905
{
889-
if (cluster.second.open_count == 0 && cluster.second.spike_count == 0)
906+
if (cluster.second.open_count == 0)
890907
{
891-
// If the cluster is completely closed, mark it as not traversable.
892908
for (auto const& index : cluster.second.turn_indices)
893909
{
894-
m_turns[index].is_turn_traversable = false;
910+
m_turns[index].is_traversable = false;
895911
}
896912
}
897913
}
@@ -904,7 +920,7 @@ struct buffered_piece_collection
904920
bool is_traversable = false;
905921
for (auto const& index : cluster.second.turn_indices)
906922
{
907-
if (m_turns[index].is_turn_traversable)
923+
if (m_turns[index].is_traversable)
908924
{
909925
// If there is one turn traversable in the cluster,
910926
// then all turns should be traversable.
@@ -916,17 +932,21 @@ struct buffered_piece_collection
916932
{
917933
for (auto const& index : cluster.second.turn_indices)
918934
{
919-
m_turns[index].is_turn_traversable = true;
935+
m_turns[index].is_traversable = true;
920936
}
921937
}
922938
}
923939
}
924940

925941
inline void enrich()
926942
{
927-
enrich_intersection_points<false, false, overlay_buffer>(m_turns,
928-
m_clusters, offsetted_rings, offsetted_rings,
929-
m_strategy);
943+
detail::overlay::enrich_discard_turns<overlay_buffer>(
944+
m_turns, m_clusters, offsetted_rings, offsetted_rings, m_strategy);
945+
detail::overlay::enrich_turns<false, false, overlay_buffer>(
946+
m_turns, offsetted_rings, offsetted_rings, m_strategy);
947+
948+
detail::overlay::get_properties_ahead<false, false>(m_turns, m_clusters, offsetted_rings,
949+
offsetted_rings, m_strategy);
930950
}
931951

932952
// Discards all rings which do have not-OK intersection points only.
@@ -935,7 +955,7 @@ struct buffered_piece_collection
935955
{
936956
for (auto const& turn : m_turns)
937957
{
938-
if (turn.is_turn_traversable)
958+
if (turn.is_traversable)
939959
{
940960
offsetted_rings[turn.operations[0].seg_id.multi_index].has_accepted_intersections = true;
941961
offsetted_rings[turn.operations[1].seg_id.multi_index].has_accepted_intersections = true;
@@ -1013,28 +1033,27 @@ struct buffered_piece_collection
10131033
}
10141034
}
10151035

1016-
inline void block_turns()
1036+
inline void discard_non_traversable_turns()
10171037
{
10181038
for (auto& turn : m_turns)
10191039
{
1020-
if (! turn.is_turn_traversable)
1040+
if (! turn.is_traversable)
10211041
{
1022-
// Discard this turn (don't set it to blocked to avoid colocated
1023-
// clusters being discarded afterwards
1042+
// Discard the non traversable turn
10241043
turn.discarded = true;
10251044
}
10261045
}
10271046
}
10281047

1029-
inline void traverse()
1048+
template <typename PieceVisitor>
1049+
inline void traverse(PieceVisitor const& piece_visitor)
10301050
{
10311051
using traverser = detail::overlay::traverse
10321052
<
10331053
false, false,
10341054
buffered_ring_collection<buffered_ring<Ring> >,
10351055
buffered_ring_collection<buffered_ring<Ring > >,
1036-
overlay_buffer,
1037-
backtrack_for_buffer
1056+
overlay_buffer
10381057
>;
10391058
std::map<ring_identifier, overlay::ring_turn_info> turn_info_per_ring;
10401059

include/boost/geometry/algorithms/detail/buffer/turn_in_original_visitor.hpp

+4-4
Original file line numberDiff line numberDiff line change
@@ -75,7 +75,7 @@ struct include_turn_policy
7575
template <typename Turn>
7676
static inline bool apply(Turn const& turn)
7777
{
78-
return turn.is_turn_traversable;
78+
return turn.is_traversable;
7979
}
8080
};
8181

@@ -89,7 +89,7 @@ struct turn_in_original_overlaps_box
8989
template <typename Box, typename Turn>
9090
inline bool apply(Box const& box, Turn const& turn) const
9191
{
92-
if (! turn.is_turn_traversable || turn.within_original)
92+
if (! turn.is_traversable || turn.within_original)
9393
{
9494
// Skip all points already processed
9595
return false;
@@ -237,7 +237,7 @@ class turn_in_original_visitor
237237
return true;
238238
}
239239

240-
if (! turn.is_turn_traversable || turn.within_original)
240+
if (! turn.is_traversable || turn.within_original)
241241
{
242242
// Skip all points already processed
243243
return true;
@@ -262,7 +262,7 @@ class turn_in_original_visitor
262262
if (code == 0)
263263
{
264264
// On border of original: always discard
265-
mutable_turn.is_turn_traversable = false;
265+
mutable_turn.is_traversable = false;
266266
}
267267

268268
// Point is inside an original ring

0 commit comments

Comments
 (0)