fix errors in coordinate extractor due to duplicated coordinates

fix offset calculation in curve detection
This commit is contained in:
Moritz Kobitzsch 2016-12-05 12:02:07 +01:00
parent 17a18b5c7c
commit a28a20a1ba
3 changed files with 183 additions and 82 deletions

View File

@ -271,11 +271,11 @@ Feature: Slipways and Dedicated Turn Lanes
| jcghf | primary | Brauerstrasse | yes |
When I route I should get
| waypoints | route | turns |
| a,i | Ebertstrasse,Ebertstrasse | depart,arrive |
| a,l | Ebertstrasse,Ebertstrasse | depart,arrive |
| a,f | Ebertstrasse,Brauerstrasse,Brauerstrasse | depart,turn right,arrive |
| a,1 | Ebertstrasse,, | depart,turn right,arrive |
| waypoints | route | turns |
| a,i | Ebertstrasse,Ebertstrasse | depart,arrive |
| a,l | Ebertstrasse,Ebertstrasse | depart,arrive |
| a,f | Ebertstrasse,Brauerstrasse,Brauerstrasse | depart,turn right,arrive |
| a,1 | Ebertstrasse,, | depart,turn slight right,arrive |
#2839
Scenario: Self-Loop

View File

@ -317,30 +317,30 @@ Feature: Simple Turns
Scenario: Curved Turn At Cross
Given the node map
"""
h
|
|
|
|
| . b - - - - - - - - - - - - - - - - - - a
| .
| .
| c
|
|
|
d
|
|
|
e |
. |
. |
g - - - - - - - - - - - - - f |
|
|
|
i
h
|
|
|
|
| . b - - - - - - - - - - - - - - - - - - - - - - - a
| .
| .
| c
|
|
|
d
|
|
|
e |
. |
. |
g - - - - - - - - - - - - - - - - - - f |
|
|
|
i
"""
And the ways
@ -443,9 +443,9 @@ Feature: Simple Turns
| ef | residential | road | 2 | yes |
When I route I should get
| waypoints | route | turns | locations |
| g,f | turn,road,road | depart,turn left,arrive | g,e,f |
| c,f | road,road,road | depart,continue right,arrive | c,b,f |
| waypoints | route | turns | locations | # |
| g,f | turn,road | depart,arrive | g,f | #could offer an additional turn at `e` if you don't detect the turn in between as curve |
| c,f | road,road,road | depart,continue right,arrive | c,b,f | |
#http://www.openstreetmap.org/search?query=52.479264%2013.295617#map=19/52.47926/13.29562
Scenario: Splitting Roads with curved split
@ -627,12 +627,14 @@ Feature: Simple Turns
| 1,h | ,allee,allee | depart,turn left,arrive |
| 2,h | ,allee,allee | depart,turn left,arrive |
#http://www.openstreetmap.org/#map=18/52.56251/13.32650
@todo
Scenario: Curved Turn on Separated Directions
Given the node map
"""
e d
f - - - - - - - - - - - - - - - c - - - - - - - - - - - j
f c - - - - - - - - - - - j
| l ' |
| ' |
| ' |
@ -680,6 +682,58 @@ Feature: Simple Turns
| j,o | Kapweg,Kapweg,Kapweg | depart,continue uturn,arrive |
| a,i | Kurt,Kurt,Kurt | depart,continue uturn,arrive |
#http://www.openstreetmap.org/#map=18/52.56251/13.32650
Scenario: Curved Turn on Separated Directions
Given the node map
"""
e d
f c - - - - - - - - - - - j
| l ' |
| ' |
| ' |
| ' |
| ' |
| n |
| |
| ' |
| |
| ' |
| |
| |
| |
|' |
| |
| |
| |
| |
g |
h - - - - - - - - - - - - - - - b - - - - - - - - - - - o
| |
| |
| |
| |
| |
| |
i a
"""
And the ways
| nodes | name | oneway | lanes | highway |
| jc | Kapweg | yes | 3 | primary |
| clngh | Kapweg | yes | | primary_link |
| hbo | Kapweg | yes | 2 | primary |
| efh | Kurt | yes | 4 | secondary |
| hi | Kurt | yes | 3 | primary |
| ab | Kurt | yes | 4 | primary |
| cd | Kurt | yes | 3 | secondary |
| bc | Kurt | yes | 2 | primary |
When I route I should get
| waypoints | route | turns |
| j,i | Kapweg,Kurt,Kurt | depart,turn left,arrive |
| j,o | Kapweg,Kapweg,Kapweg | depart,continue uturn,arrive |
| a,i | Kurt,Kurt,Kurt | depart,continue uturn,arrive |
#http://www.openstreetmap.org/#map=19/52.53731/13.36033
Scenario: Splitting Road to Left
Given the node map
@ -1112,8 +1166,9 @@ Feature: Simple Turns
"""
And the ways
| nodes | name | highway | lanes |
| abcdefghijklmnopc | circled | residential | 1 |
| nodes | name | highway | lanes | oneway |
| abc | circled | residential | 1 | no |
| cdefghijklmnopc | circled | residential | 1 | yes |
When I route I should get
| waypoints | bearings | route | turns |
@ -1168,3 +1223,40 @@ Feature: Simple Turns
When I route I should get
| waypoints | route |
| a,e | ab,bcde,bcde |
@3401
Scenario: Curve With Duplicated Coordinates
Given the node locations
| node | lat | lon | # |
| a | 0.9999280745650984 | 1.0 | |
| b | 0.9999280745650984 | 1.0000179813587253 | |
| c | 0.9999280745650984 | 1.0000359627174509 | |
| d | 0.9999460559238238 | 1.0000674300952204 | |
| e | 0.9999640372825492 | 1.0000809161142643 | |
| f | 0.9999820186412746 | 1.0000854114539457 | |
| g | 1.0 | 1.0000854114539457 | |
| h | 1.0 | 1.0000854114539457 | #same as g |
| z | 0.9999100932063729 | 1.0000179813587253 | |
# g
# |
# f
# '
# e
# '
# d
# '
#a - b - c
# |
# z
And the ways
| nodes | oneway | lanes | # |
| ab | yes | 1 | |
| zb | yes | 1 | |
| bcdefgh | yes | 1 | #intentional duplication |
# we don't care for turn instructions, this is a coordinate extraction bug check
When I route I should get
| waypoints | route | intersections |
| a,g | ab,bcdefgh,bcdefgh | true:90;true:45 false:180 false:270;true:180 |

View File

@ -125,13 +125,13 @@ util::Coordinate CoordinateExtractor::ExtractRepresentativeCoordinate(
// due to repeated coordinates / smaller offset errors we skip over the very first parts of the
// coordinate set to add a small level of fault tolerance
const constexpr double distance_to_skip_over_due_to_coordinate_inaccuracies = 2;
const constexpr double skipping_inaccuracies_distance = 2;
// fallback, mostly necessary for dead ends
if (intersection_node == to_node)
{
const auto result = ExtractCoordinateAtLength(
distance_to_skip_over_due_to_coordinate_inaccuracies, coordinates);
skipping_inaccuracies_distance, coordinates);
BOOST_ASSERT(is_valid_result(coordinates.back()));
return result;
}
@ -147,7 +147,7 @@ util::Coordinate CoordinateExtractor::ExtractRepresentativeCoordinate(
if (turn_edge_data.roundabout || turn_edge_data.circular)
{
const auto result = ExtractCoordinateAtLength(
distance_to_skip_over_due_to_coordinate_inaccuracies, coordinates);
skipping_inaccuracies_distance, coordinates);
BOOST_ASSERT(is_valid_result(result));
return result;
}
@ -235,7 +235,7 @@ util::Coordinate CoordinateExtractor::ExtractRepresentativeCoordinate(
// if we are now left with two, well than we don't have to worry, or the segment is very small
if (coordinates.size() == 2 ||
total_distance <= distance_to_skip_over_due_to_coordinate_inaccuracies)
total_distance <= skipping_inaccuracies_distance)
{
BOOST_ASSERT(is_valid_result(coordinates.back()));
return coordinates.back();
@ -253,7 +253,7 @@ util::Coordinate CoordinateExtractor::ExtractRepresentativeCoordinate(
if (coordinates.front() == coordinates.back())
{
const auto result = ExtractCoordinateAtLength(
distance_to_skip_over_due_to_coordinate_inaccuracies, coordinates);
skipping_inaccuracies_distance, coordinates);
BOOST_ASSERT(is_valid_result(result));
return result;
}
@ -337,38 +337,9 @@ util::Coordinate CoordinateExtractor::ExtractRepresentativeCoordinate(
return result;
}
if (IsCurve(coordinates,
segment_distances,
total_distance,
considered_lanes * 0.5 * ASSUMED_LANE_WIDTH,
turn_edge_data))
{
if (total_distance <= distance_to_skip_over_due_to_coordinate_inaccuracies)
return coordinates.back();
/*
* In curves we now have to distinguish between larger curves and tiny curves modelling the
* actual turn in the beginnig.
*
* We distinguish between turns that simply model the initial way of getting onto the
* destination lanes and the ones that performa a larger turn.
*/
const double offset =
std::min(0.5 * considered_lanes * ASSUMED_LANE_WIDTH, 0.2 * segment_distances.back());
coordinates = TrimCoordinatesToLength(std::move(coordinates), offset, segment_distances);
BOOST_ASSERT(coordinates.size() >= 2);
segment_distances.resize(coordinates.size());
segment_distances.back() = util::coordinate_calculation::haversineDistance(
*(coordinates.end() - 2), coordinates.back());
const auto vector_head = coordinates.back();
coordinates =
TrimCoordinatesToLength(std::move(coordinates), 0.5 * offset, segment_distances);
BOOST_ASSERT(coordinates.size() >= 2);
const auto result =
GetCorrectedCoordinate(turn_coordinate, coordinates.back(), vector_head);
BOOST_ASSERT(is_valid_result(result));
return result;
}
// We check offsets before curves to avoid detecting lane offsets due to large roads as curves
// (think major highway here). If the road is wide, it can have quite a few coordinates in the
// beginning.
if (IsDirectOffset(coordinates,
straight_index,
straight_distance,
@ -387,6 +358,40 @@ util::Coordinate CoordinateExtractor::ExtractRepresentativeCoordinate(
return result;
}
if (IsCurve(coordinates,
segment_distances,
total_distance,
considered_lanes * 0.5 * ASSUMED_LANE_WIDTH,
turn_edge_data))
{
if (total_distance <= skipping_inaccuracies_distance)
return coordinates.back();
/*
* In curves we now have to distinguish between larger curves and tiny curves modelling the
* actual turn in the beginnig.
*
* We distinguish between turns that simply model the initial way of getting onto the
* destination lanes and the ones that performa a larger turn.
*/
coordinates =
TrimCoordinatesToLength(std::move(coordinates),
2 * skipping_inaccuracies_distance,
segment_distances);
BOOST_ASSERT(coordinates.size() >= 2);
segment_distances.resize(coordinates.size());
segment_distances.back() = util::coordinate_calculation::haversineDistance(
*(coordinates.end() - 2), coordinates.back());
const auto vector_head = coordinates.back();
coordinates = TrimCoordinatesToLength(std::move(coordinates),
skipping_inaccuracies_distance,
segment_distances);
BOOST_ASSERT(coordinates.size() >= 2);
const auto result =
GetCorrectedCoordinate(turn_coordinate, coordinates.back(), vector_head);
BOOST_ASSERT(is_valid_result(result));
return result;
}
{
// skip over the first coordinates, in specific the assumed lane count. We add a small
// safety factor, to not overshoot on the regression
@ -600,6 +605,9 @@ CoordinateExtractor::GetCoordinatesAlongRoad(const NodeID intersection_node,
std::back_inserter(result),
compressedGeometryToCoordinate);
}
// filter duplicated coordinates
auto end = std::unique(result.begin(), result.end());
result.erase(end, result.end());
return result;
}
}
@ -693,12 +701,12 @@ bool CoordinateExtractor::IsCurve(const std::vector<util::Coordinate> &coordinat
std::tie(has_up_down_deviation, maximum_deviation_index, maximum_deviation) =
[&coordinates, get_deviation]() -> std::tuple<bool, std::size_t, double> {
const auto increasing = [&](const util::Coordinate lhs, const util::Coordinate rhs) {
return get_deviation(coordinates.front(), coordinates.back(), lhs) <=
return get_deviation(coordinates.front(), coordinates.back(), lhs) <
get_deviation(coordinates.front(), coordinates.back(), rhs);
};
const auto decreasing = [&](const util::Coordinate lhs, const util::Coordinate rhs) {
return get_deviation(coordinates.front(), coordinates.back(), lhs) >=
return get_deviation(coordinates.front(), coordinates.back(), lhs) >
get_deviation(coordinates.front(), coordinates.back(), rhs);
};
@ -709,16 +717,17 @@ bool CoordinateExtractor::IsCurve(const std::vector<util::Coordinate> &coordinat
return std::make_tuple(
true, 1, get_deviation(coordinates.front(), coordinates.back(), coordinates[1]));
const auto maximum_itr =
const auto one_past_maximum_iter =
std::is_sorted_until(coordinates.begin() + 1, coordinates.end(), increasing);
if (maximum_itr == coordinates.end())
if (one_past_maximum_iter == coordinates.end())
return std::make_tuple(true, coordinates.size() - 1, 0.);
else if (std::is_sorted(maximum_itr, coordinates.end(), decreasing))
return std::make_tuple(
true,
std::distance(coordinates.begin(), maximum_itr),
get_deviation(coordinates.front(), coordinates.back(), *maximum_itr));
else if (std::is_sorted(one_past_maximum_iter, coordinates.end(), decreasing))
return std::make_tuple(true,
std::distance(coordinates.begin(), one_past_maximum_iter) - 1,
get_deviation(coordinates.front(),
coordinates.back(),
*(one_past_maximum_iter - 1)));
else
return std::make_tuple(false, 0, 0.);
}();
@ -731,7 +740,7 @@ bool CoordinateExtractor::IsCurve(const std::vector<util::Coordinate> &coordinat
// if the maximum deviation is at a quarter of the total curve, we are probably looking at a
// normal turn
const auto distance_to_max_deviation = std::accumulate(
segment_distances.begin(), segment_distances.begin() + maximum_deviation_index, 0.);
segment_distances.begin(), segment_distances.begin() + maximum_deviation_index + 1, 0.);
if ((distance_to_max_deviation <= 0.35 * segment_length ||
maximum_deviation < std::max(0.3 * considered_lane_width, 0.5 * ASSUMED_LANE_WIDTH)) &&