[fix] assign next turn

Fixes issue #1250
This commit is contained in:
Barend Gehrels 2024-02-28 21:40:40 +00:00
parent 29a209d329
commit 78894ef697
3 changed files with 89 additions and 55 deletions

View File

@ -107,69 +107,86 @@ inline void enrich_sort(Operations& operations,
}
// Assign travel-to-vertex/ip index for each turn.
template <typename Operations, typename Turns>
inline void enrich_assign(Operations& operations, Turns& turns,
bool check_turns)
bool check_consecutive_turns)
{
if (operations.empty())
{
return;
}
// Assign travel-to-vertex/ip index for each turning point.
// Iterator "next" is circular
geometry::ever_circling_range_iterator<Operations const> next(operations);
++next;
for (auto const& indexed : operations)
for_each_with_index(operations, [&](std::size_t index, auto const& indexed)
{
auto& turn = turns[indexed.turn_index];
auto& op = turn.operations[indexed.operation_index];
if (check_turns && indexed.turn_index == next->turn_index)
std::size_t next_index = index + 1 < operations.size() ? index + 1 : 0;
auto advance = [&operations](auto index)
{
// Normal behaviour: next points at next turn, increase next.
// For dissolve this should not be done, turn_index is often
// the same for two consecutive operations
++next;
std::size_t const result = index + 1;
return result >= operations.size() ? 0 : result;
};
auto next_turn = [&operations, &turns, &next_index]()
{
return turns[operations[next_index].turn_index];
};
auto next_operation = [&operations, &turns, &next_index]()
{
auto const& next_turn = turns[operations[next_index].turn_index];
return next_turn.operations[operations[next_index].operation_index];
};
if (check_consecutive_turns
&& indexed.turn_index == operations[next_index].turn_index
&& op.seg_id == next_operation().seg_id)
{
// If the two operations on the same turn are ordered consecutively,
// and they are on the same segment, then the turn where to travel to should
// be considered one further. Therefore next is increased.
//
// It often happens in buffer, in these configurations:
// +---->--+
// | |
// | +->-*---->
// | | |
// ^ +-<-+
// If the next index is not corrected, the small rectangle
// will be kept in the output.
// This is a normal situation and occurs, for example, in every concave bend.
// In general it should always travel from turn to next turn.
// Only in some circumstances traveling to the same turn is necessary, for example
// if there is only one turn in the outer ring.
//
// (For dissolve this is not done, turn_index is often
// the same for two consecutive operations - but the conditions are changed
// and this should be verified again)
next_index = advance(next_index);
}
// Cluster behaviour: next should point after cluster, unless
// their seg_ids are not the same
// (For dissolve, this is still to be examined - TODO)
while (turn.is_clustered()
&& indexed.turn_index != next->turn_index
&& turn.cluster_id == turns[next->turn_index].cluster_id
&& op.seg_id == turns[next->turn_index].operations[next->operation_index].seg_id)
&& turn.cluster_id == next_turn().cluster_id
&& op.seg_id == next_operation().seg_id
&& indexed.turn_index != operations[next_index].turn_index)
{
++next;
next_index = advance(next_index);
}
auto const& next_turn = turns[next->turn_index];
auto const& next_op = next_turn.operations[next->operation_index];
op.enriched.travels_to_ip_index
= static_cast<signed_size_type>(next->turn_index);
= static_cast<signed_size_type>(operations[next_index].turn_index);
op.enriched.travels_to_vertex_index
= next->subject->seg_id.segment_index;
= operations[next_index].subject->seg_id.segment_index;
auto const& next_op = next_operation();
if (op.seg_id.segment_index == next_op.seg_id.segment_index
&& op.fraction < next_op.fraction)
&& op.fraction < next_op.fraction)
{
// Next turn is located further on same segment
// assign next_ip_index
// (this is one not circular therefore fraction is considered)
op.enriched.next_ip_index = static_cast<signed_size_type>(next->turn_index);
// Next turn is located further on same segment: assign next_ip_index
op.enriched.next_ip_index = static_cast<signed_size_type>(operations[next_index].turn_index);
}
});
if (! check_turns)
{
++next;
}
}
// DEBUG
#ifdef BOOST_GEOMETRY_DEBUG_ENRICH
for (auto const& indexed_op : operations)
{
@ -191,8 +208,6 @@ inline void enrich_assign(Operations& operations, Turns& turns,
<< std::endl;
}
#endif
// END DEBUG
}
template <typename Operations, typename Turns>
@ -490,13 +505,6 @@ inline void enrich_intersection_points(Turns& turns,
pair.second, turns,
geometry1, geometry2,
robust_policy, strategy);
#ifdef BOOST_GEOMETRY_DEBUG_ENRICH
std::cout << "ENRICH-sort Ring " << pair.first << std::endl;
for (auto const& op : pair.second)
{
std::cout << op.turn_index << " " << op.operation_index << std::endl;
}
#endif
}
if (has_colocations)

View File

@ -7,6 +7,7 @@
foreach(item IN ITEMS
buffer
buffer_gc
buffer_variable_width
)
boost_geometry_add_unit_test("algorithms" ${item})
endforeach()

View File

@ -34,7 +34,9 @@ static std::string const two_bends = "LINESTRING(0 0,4 5,7 4,10 6)";
static std::string const bend_near_start1 = "LINESTRING(0 0,1 0,5 2)";
static std::string const bend_near_start2 = "LINESTRING(0 0,1 0,2 1.5,5 3)";
static std::string const overlapping = "LINESTRING(0 0,4 5,7 4,10 6, 10 2,2 2)";
static std::string const overlapping = "LINESTRING(0 0,4 5,7 4,10 6,10 2,2 2)";
static std::string const overlapping_rev = "LINESTRING(2 2,10 2,10 6,7 4,4 5,0 0)";
static std::string const curve = "LINESTRING(2 7,3 5,5 4,7 5,8 7)";
static std::string const tripod = "LINESTRING(5 0,5 5,1 8,5 5,9 8)"; // with spike
@ -111,6 +113,8 @@ static std::string const issue_803 = "LINESTRING(2773.6899360413681 -17.49335640
static std::string const issue_988 = "LINESTRING(0.10144 0.034912,0.106079 0.035156,0.109375 0.034302,0.114502 0.035889,0.116333 0.036743,0.117065 0.036499,0.121582 0.035156,0.12439 0.029175,0.123779 0.026978,0.12146 0.025513,0.119507 0.025513,0.118164 0.025513,0.114624 0.025757,0.111694 0.026001,0.108887 0.02832,0.105957 0.028442,0.099854 0.027344,0.095581 0.029419,0.093506 0.031128,0.090576 0.032593,0.085571 0.032959,0.082153 0.035522,0.081421 0.039307,0.082275 0.044067,0.083862 0.047485,0.08606 0.049805,0.087891 0.051025,0.090942 0.05188,0.094727 0.051392,0.100098 0.050049,0.10144 0.05249,0.100952 0.054932,0.098633 0.05835,0.098267 0.062134,0.098755 0.064697,0.098511 0.067383,0.113892 0.068848,0.110718 0.065552,0.109619 0.064331,0.111084 0.063965,0.118042 0.0625,0.115234 0.049805,0.117676 0.049194,0.118774 0.046997,0.119385 0.04541,0.119507 0.043945,0.116089 0.041138,0.116089 0.041016,0.11438 0.040894,0.11145 0.041016,0.109009 0.042114,0.106079 0.04248,0.102417 0.041138,0.102051 0.040039)";
static std::string const issue_1084 = "LINESTRING(269.3 -7.03, 270.23 -3.57, 270.54 0, 270.54 100, 270.23 103.57, 269.3 107.03, 267.79 110.27, 265.73 113.2, 263.2 115.73, 258.89 118.43, 254.28 108.54, 248.52 109, 80 97.21, 72.71 95.87, 67.46 93.82, 62.61 90.92, 58.32 87.27, 54.69 82.95, 51.83 78.08, 49.81 72.81, 48.7 67.28, 48.45 63.38, 48.52 34.87, 49.29 29.26, 50.96 23.87, 54.69 17.05, 58.32 12.73, 62.61 9.08, 65.57 7.18, 70.68 4.81, 76.12 3.31, 80 2.79, 248.52 -9, 254.28 -8.54, 258.89 -18.43, 263.2 -15.73, 265.73 -13.2, 267.79 -10.27, 269.3 -7.03, 270.23 -3.57, 270.54 0, 270.54 100, 270.23 103.57, 269.3 107.03, 267.79 110.27, 265.73 113.2, 264 114.93, 256.24 107.17, 251.86 108.16, 248.58 108.2, 76.24 95.9, 70.93 94.43, 65.94 92.11, 61.4 88.99, 57.44 85.16, 54.18 80.72, 51.69 75.8, 50.06 70.54, 49.25 63.38, 49.32 34.93, 50.06 29.46, 51.69 24.2, 55.36 17.49, 58.9 13.28, 63.1 9.71, 67.83 6.89, 70.93 5.57, 76.24 4.1, 80.06 3.59, 248.58 -8.2, 251.86 -8.16, 256.24 -7.17, 258.89 -18.43)";
static std::string const issue_1250 = "LINESTRING(3 1, 4 2, 4 4, 2 4, 2 2, 3 2)";
static std::string const issue_1250_rev = "LINESTRING(3 2, 2 2, 2 4, 4 4, 4 2, 3 1)";
template <bool Clockwise, typename P>
void test_all()
@ -179,23 +183,38 @@ void test_all()
test_one<linestring, polygon>("bend_near_start1", bend_near_start1, join_round, end_flat, 109.2625, 9.0);
test_one<linestring, polygon>("bend_near_start2", bend_near_start2, join_round, end_flat, 142.8709, 9.0);
// Next (and all similar cases) which a offsetted-one-sided buffer has to be fixed. TODO
// Next (and all similar cases) which a offsetted-one-sided buffer has to be supported. TODO
//test_one<linestring, polygon>("two_bends_neg", two_bends, join_miter, end_flat, 99, +1.5, settings, -1.0);
//test_one<linestring, polygon>("two_bends_pos", two_bends, join_miter, end_flat, 99, -1.5, settings, +1.0);
//test_one<linestring, polygon>("two_bends_neg", two_bends, join_round, end_flat,99, +1.5, settings, -1.0);
//test_one<linestring, polygon>("two_bends_neg", two_bends, join_round, end_flat,99, +1.5, settings, -1.0);
//test_one<linestring, polygon>("two_bends_pos", two_bends, join_round, end_flat, 99, -1.5, settings, +1.0);
test_one<linestring, polygon>("overlapping150", overlapping, join_round, end_flat, 65.6786, 1.5);
test_one<linestring, polygon>("overlapping150", overlapping, join_miter, end_flat, 68.140, 1.5);
test_one<linestring, polygon>("overlapping_50", overlapping, join_round, end_flat, 24.6326, 0.5);
test_one<linestring, polygon>("overlapping_50", overlapping, join_miter, end_flat, 24.9147, 0.5);
test_one<linestring, polygon>("overlapping_150", overlapping, join_round, end_flat, 65.6786, 1.5);
test_one<linestring, polygon>("overlapping_150", overlapping, join_miter, end_flat, 68.140, 1.5);
test_one<linestring, polygon>("overlapping_rev_50", overlapping_rev, join_round, end_flat, 24.6326, 0.5);
test_one<linestring, polygon>("overlapping_rev_50", overlapping_rev, join_miter, end_flat, 24.9147, 0.5);
test_one<linestring, polygon>("overlapping_rev_150", overlapping_rev, join_round, end_flat, 65.6786, 1.5);
test_one<linestring, polygon>("overlapping_rev_150", overlapping_rev, join_miter, end_flat, 68.140, 1.5);
// Different cases with intersection points on flat and (left/right from line itself)
test_one<linestring, polygon>("overlapping_asym_150_010", overlapping, join_round, end_flat, 48.308, 1.5, settings, 0.25);
test_one<linestring, polygon>("overlapping_asym_150_010", overlapping, join_miter, end_flat, 50.770, 1.5, settings, 0.25);
test_one<linestring, polygon>("overlapping_asym_150_025", overlapping, join_round, end_flat, 48.308, 1.5, settings, 0.25);
test_one<linestring, polygon>("overlapping_asym_150_025", overlapping, join_miter, end_flat, 50.770, 1.5, settings, 0.25);
test_one<linestring, polygon>("overlapping_asym_150_075", overlapping, join_round, end_flat, 58.506, 1.5, settings, 0.75);
test_one<linestring, polygon>("overlapping_asym_150_075", overlapping, join_miter, end_flat, 60.985, 1.5, settings, 0.75);
test_one<linestring, polygon>("overlapping_asym_150_100", overlapping, join_round, end_flat, 62.514, 1.5, settings, 1.0);
test_one<linestring, polygon>("overlapping_asym_150_100", overlapping, join_miter, end_flat, 64.984, 1.5, settings, 1.0);
// The reverse cases need to reverse the distance too, for the same result
test_one<linestring, polygon>("overlapping_rev_asym_150_025", overlapping_rev, join_round, end_flat, 48.308, 0.25, settings, 1.5);
test_one<linestring, polygon>("overlapping_rev_asym_150_025", overlapping_rev, join_miter, end_flat, 50.770, 0.25, settings, 1.5);
test_one<linestring, polygon>("overlapping_rev_asym_150_075", overlapping_rev, join_round, end_flat, 58.506, 0.75, settings, 1.5);
test_one<linestring, polygon>("overlapping_rev_asym_150_075", overlapping_rev, join_miter, end_flat, 60.985, 0.75, settings, 1.5);
test_one<linestring, polygon>("overlapping_rev_asym_150_100", overlapping_rev, join_round, end_flat, 62.514, 1.0, settings, 1.5);
test_one<linestring, polygon>("overlapping_rev_asym_150_100", overlapping_rev, join_miter, end_flat, 64.984, 1.0, settings, 1.5);
// Having flat end
test_one<linestring, polygon>("for_collinear", for_collinear, join_round, end_flat, 68.561, 2.0);
test_one<linestring, polygon>("for_collinear", for_collinear, join_miter, end_flat, 72, 2.0);
@ -326,6 +345,12 @@ void test_all()
using bg::strategy::buffer::end_round;
test_one<linestring, polygon>("issue_1084", issue_1084, join_round(10), end_round(10), 13200.83, 10.0);
}
{
using bg::strategy::buffer::join_miter;
using bg::strategy::buffer::end_flat;
test_one<linestring, polygon>("issue_1250", issue_1250, join_miter(5), end_flat(), 8.39277, 0.5);
test_one<linestring, polygon>("issue_1250_rev", issue_1250_rev, join_miter(5), end_flat(), 8.39277, 0.5);
}
test_one<linestring, polygon>("mysql_report_2015_06_11",
mysql_report_2015_06_11, join_round32, end_round32,