Skip to content

Commit

Permalink
[fix] assign next turn
Browse files Browse the repository at this point in the history
Fixes issue #1250
  • Loading branch information
barendgehrels committed Mar 13, 2024
1 parent 29a209d commit 78894ef
Show file tree
Hide file tree
Showing 3 changed files with 89 additions and 55 deletions.
Expand Up @@ -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)
{
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)
{
// 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;
// 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)
{
// 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);
}

if (! check_turns)
&& op.fraction < next_op.fraction)
{
++next;
// 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);
}
}
});

// DEBUG
#ifdef BOOST_GEOMETRY_DEBUG_ENRICH
for (auto const& indexed_op : operations)
{
Expand All @@ -191,8 +208,6 @@ inline void enrich_assign(Operations& operations, Turns& turns,
<< std::endl;
}
#endif
// END DEBUG

}

template <typename Operations, typename Turns>
Expand Down Expand Up @@ -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)
Expand Down
1 change: 1 addition & 0 deletions test/algorithms/buffer/CMakeLists.txt
Expand Up @@ -7,6 +7,7 @@
foreach(item IN ITEMS
buffer
buffer_gc
buffer_variable_width
)
boost_geometry_add_unit_test("algorithms" ${item})
endforeach()
Expand Down
39 changes: 32 additions & 7 deletions test/algorithms/buffer/buffer_linestring.cpp
Expand Up @@ -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

Expand Down Expand Up @@ -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()
Expand Down Expand Up @@ -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);
Expand Down Expand Up @@ -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,
Expand Down

0 comments on commit 78894ef

Please sign in to comment.