Remove assertions that could be triggered by bad data. (#3469)

When two consecutive nodes have identical coordinates, there is no valid
bearing.  For now, make equal nodes have bearing 0.

Full fix still needs to be done via https://github.com/Project-OSRM/osrm-backend/issues/3470.
This commit is contained in:
Moritz Kobitzsch
2017-01-07 02:10:02 +01:00
committed by Daniel Patterson
parent f7e8581a1b
commit 15c8fd326f
9 changed files with 132 additions and 42 deletions
+47 -36
View File
@@ -93,23 +93,21 @@ util::Coordinate CoordinateExtractor::ExtractRepresentativeCoordinate(
const std::uint8_t intersection_lanes,
std::vector<util::Coordinate> coordinates) const
{
const auto is_valid_result = [&](const util::Coordinate coordinate) {
// check if the coordinate is equal to the interseciton coordinate
const auto not_same_as_start = [&](const util::Coordinate coordinate) {
return util::Coordinate(traversed_in_reverse
? node_coordinates[to_node]
: node_coordinates[intersection_node]) != coordinate;
};
// this is only used for debug purposes in assertions. We don't want warnings about it
(void)is_valid_result;
// the lane count might not always be set. We need to assume a positive number, though. Here we
// select the number of lanes to operate on
const auto considered_lanes =
GetOffsetCorrectionFactor(node_based_graph.GetEdgeData(turn_edge).road_classification) *
((intersection_lanes == 0) ? ASSUMED_LANE_COUNT : intersection_lanes);
(void)not_same_as_start;
// Fallback. These roads are small broken self-loops that shouldn't be in the data at all
if (intersection_node == to_node)
{
BOOST_ASSERT(coordinates.size() >= 2);
return coordinates[1];
}
/* if we are looking at a straight line, we don't care where exactly the coordinate
* is. Simply return the final coordinate. Turn angles/turn vectors are the same no matter which
@@ -117,8 +115,8 @@ util::Coordinate CoordinateExtractor::ExtractRepresentativeCoordinate(
*/
if (coordinates.size() <= 2)
{
// Here we can't check for validity, due to possible dead-ends with repeated coordinates
// BOOST_ASSERT(is_valid_result(coordinates.back()));
// TODO: possibly re-enable with https://github.com/Project-OSRM/osrm-backend/issues/3470
// BOOST_ASSERT(not_same_as_start(result));
return coordinates.back();
}
@@ -130,22 +128,19 @@ util::Coordinate CoordinateExtractor::ExtractRepresentativeCoordinate(
if (intersection_node == to_node)
{
const auto result = ExtractCoordinateAtLength(skipping_inaccuracies_distance, coordinates);
BOOST_ASSERT(is_valid_result(result));
// TODO: possibly re-enable with https://github.com/Project-OSRM/osrm-backend/issues/3470
// BOOST_ASSERT(not_same_as_start(result));
return result;
}
// If this reduction leaves us with only two coordinates, the turns/angles are represented in a
// valid way. Only curved roads and other difficult scenarios will require multiple coordinates.
if (coordinates.size() == 2)
return coordinates.back();
const auto &turn_edge_data = node_based_graph.GetEdgeData(turn_edge);
// roundabouts, check early to avoid other costly checks
if (turn_edge_data.roundabout || turn_edge_data.circular)
{
const auto result = ExtractCoordinateAtLength(skipping_inaccuracies_distance, coordinates);
BOOST_ASSERT(is_valid_result(result));
// TODO: possibly re-enable with https://github.com/Project-OSRM/osrm-backend/issues/3470
// BOOST_ASSERT(not_same_as_start(result));
return result;
}
@@ -166,21 +161,34 @@ util::Coordinate CoordinateExtractor::ExtractRepresentativeCoordinate(
util::coordinate_calculation::haversineDistance(turn_coordinate, coordinates[1]) <
ASSUMED_LANE_WIDTH)
{
const auto result =
GetCorrectedCoordinate(turn_coordinate, coordinates[1], coordinates.back());
BOOST_ASSERT(is_valid_result(result));
return result;
}
else
{
BOOST_ASSERT(is_valid_result(coordinates.back()));
return coordinates.back();
const auto initial_distance =
util::coordinate_calculation::haversineDistance(turn_coordinate, coordinates[1]);
const auto total_distance = util::coordinate_calculation::haversineDistance(
turn_coordinate, coordinates.back());
if (initial_distance > ASSUMED_LANE_WIDTH && total_distance > initial_distance)
{
const auto result =
GetCorrectedCoordinate(turn_coordinate, coordinates[1], coordinates.back());
BOOST_ASSERT(not_same_as_start(result));
return result;
}
}
// TODO: possibly re-enable with
// https://github.com/Project-OSRM/osrm-backend/issues/3470
// BOOST_ASSERT(not_same_as_start(coordinates.back()));
return coordinates.back();
}
const auto first_distance =
util::coordinate_calculation::haversineDistance(coordinates[0], coordinates[1]);
// the lane count might not always be set. We need to assume a positive number, though. Here we
// select the number of lanes to operate on
const auto considered_lanes =
GetOffsetCorrectionFactor(node_based_graph.GetEdgeData(turn_edge).road_classification) *
((intersection_lanes == 0) ? ASSUMED_LANE_COUNT : intersection_lanes);
/* if the very first coordinate along the road is reasonably far away from the road, we assume
* the coordinate to correctly represent the turn. This could probably be improved using
* information on the very first turn angle (requires knowledge about previous road) and the
@@ -194,7 +202,7 @@ util::Coordinate CoordinateExtractor::ExtractRepresentativeCoordinate(
if (first_coordinate_is_far_away)
{
BOOST_ASSERT(is_valid_result(coordinates[1]));
BOOST_ASSERT(not_same_as_start(coordinates[1]));
return coordinates[1];
}
@@ -233,7 +241,8 @@ 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 <= skipping_inaccuracies_distance)
{
BOOST_ASSERT(is_valid_result(coordinates.back()));
// TODO: possibly re-enable with https://github.com/Project-OSRM/osrm-backend/issues/3470
// BOOST_ASSERT(not_same_as_start(coordinates.back()));
return coordinates.back();
}
@@ -250,12 +259,12 @@ util::Coordinate CoordinateExtractor::ExtractRepresentativeCoordinate(
{
const auto result =
ExtractCoordinateAtLength(skipping_inaccuracies_distance, coordinates);
BOOST_ASSERT(is_valid_result(result));
BOOST_ASSERT(not_same_as_start(result));
return result;
}
else
{
BOOST_ASSERT(is_valid_result(coordinates.back()));
BOOST_ASSERT(not_same_as_start(coordinates.back()));
return coordinates.back();
}
}
@@ -295,7 +304,7 @@ util::Coordinate CoordinateExtractor::ExtractRepresentativeCoordinate(
{
// skip over repeated coordinates
const auto result = ExtractCoordinateAtLength(5, coordinates, segment_distances);
BOOST_ASSERT(is_valid_result(result));
BOOST_ASSERT(not_same_as_start(result));
return result;
}
@@ -329,7 +338,7 @@ util::Coordinate CoordinateExtractor::ExtractRepresentativeCoordinate(
.second;
const auto result =
GetCorrectedCoordinate(turn_coordinate, coord_between_front, coord_between_back);
BOOST_ASSERT(is_valid_result(result));
BOOST_ASSERT(not_same_as_start(result));
return result;
}
@@ -350,7 +359,7 @@ util::Coordinate CoordinateExtractor::ExtractRepresentativeCoordinate(
const auto result = GetCorrectedCoordinate(
turn_coordinate, coordinates[offset_index], coordinates[offset_index + 1]);
BOOST_ASSERT(is_valid_result(result));
BOOST_ASSERT(not_same_as_start(result));
return result;
}
@@ -381,7 +390,7 @@ util::Coordinate CoordinateExtractor::ExtractRepresentativeCoordinate(
BOOST_ASSERT(coordinates.size() >= 2);
const auto result =
GetCorrectedCoordinate(turn_coordinate, coordinates.back(), vector_head);
BOOST_ASSERT(is_valid_result(result));
BOOST_ASSERT(not_same_as_start(result));
return result;
}
@@ -407,7 +416,7 @@ util::Coordinate CoordinateExtractor::ExtractRepresentativeCoordinate(
{
const auto result = GetCorrectedCoordinate(
turn_coordinate, regression_line_trimmed.first, regression_line_trimmed.second);
BOOST_ASSERT(is_valid_result(result));
BOOST_ASSERT(not_same_as_start(result));
return result;
}
}
@@ -417,7 +426,7 @@ util::Coordinate CoordinateExtractor::ExtractRepresentativeCoordinate(
// intersection.
const auto result =
ExtractCoordinateAtLength(LOOKAHEAD_DISTANCE_WITHOUT_LANES, coordinates, segment_distances);
BOOST_ASSERT(is_valid_result(result));
BOOST_ASSERT(not_same_as_start(result));
return result;
}
@@ -984,7 +993,9 @@ CoordinateExtractor::GetCorrectedCoordinate(const util::Coordinate fixpoint,
// we can use the end-coordinate
if (util::coordinate_calculation::haversineDistance(vector_base, vector_head) <
DESIRED_COORDINATE_DIFFERENCE)
{
return vector_head;
}
else
{
/* to correct for the initial offset, we move the lookahead coordinate close
@@ -5,8 +5,10 @@
#include "util/bearing.hpp"
#include "util/coordinate_calculation.hpp"
#include "util/log.hpp"
#include <algorithm>
#include <cmath>
#include <functional> // mem_fn
#include <limits>
#include <numeric>
@@ -106,6 +108,19 @@ IntersectionGenerator::ComputeIntersectionShape(const NodeID node_at_center_of_i
bearing =
util::coordinate_calculation::bearing(turn_coordinate, coordinate_along_edge_leaving);
// OSM data sometimes contains duplicated nodes with identical coordinates, or
// because of coordinate precision rounding, end up at the same coordinate.
// It's impossible to calculate a bearing between these, so we log a warning
// that the data should be checked.
// The bearing calculation should return 0 in these cases, which may not be correct,
// but is at least not random.
if (turn_coordinate == coordinate_along_edge_leaving)
{
util::Log(logDEBUG) << "Zero length segment at " << coordinate_along_edge_leaving
<< " could cause invalid intersection exit bearing.";
BOOST_ASSERT(std::abs(bearing) <= 0.1);
}
intersection.push_back({edge_connected_to_intersection, bearing, segment_length});
}
@@ -204,6 +204,20 @@ bool RoundaboutHandler::qualifiesAsRoundaboutIntersection(
result.push_back(
util::coordinate_calculation::bearing(src_coordinate, next_coordinate));
// OSM data sometimes contains duplicated nodes with identical coordinates, or
// because of coordinate precision rounding, end up at the same coordinate.
// It's impossible to calculate a bearing between these, so we log a warning
// that the data should be checked.
// The bearing calculation should return 0 in these cases, which may not be correct,
// but is at least not random.
if (src_coordinate == next_coordinate)
{
util::Log(logDEBUG) << "Zero length segment at " << next_coordinate
<< " could cause invalid roundabout exit bearings";
BOOST_ASSERT(std::abs(result.back()) <= 0.1);
}
break;
}
}
+11 -4
View File
@@ -300,12 +300,18 @@ operator()(const NodeID /*nid*/, const EdgeID source_edge_id, Intersection inter
//
// Sliproad Not a Sliproad
{
const auto &extractor = intersection_generator.GetCoordinateExtractor();
const auto &coordinate_extractor = intersection_generator.GetCoordinateExtractor();
const NodeID start = intersection_node_id; // b
const EdgeID edge = sliproad_edge; // bd
const auto coords = extractor.GetForwardCoordinatesAlongRoad(start, edge);
const auto coords = coordinate_extractor.GetForwardCoordinatesAlongRoad(start, edge);
// due to filtering of duplicated coordinates, we can end up with empty segments.
// this can only happen as long as
// https://github.com/Project-OSRM/osrm-backend/issues/3470 persists
if (coords.size() < 2)
continue;
BOOST_ASSERT(coords.size() >= 2);
// Now keep start and end coordinate fix and check for curvature
@@ -543,14 +549,15 @@ bool SliproadHandler::nextIntersectionIsTooFarAway(const NodeID start, const Edg
BOOST_ASSERT(start != SPECIAL_NODEID);
BOOST_ASSERT(onto != SPECIAL_EDGEID);
const auto &extractor = intersection_generator.GetCoordinateExtractor();
const auto &coordinate_extractor = intersection_generator.GetCoordinateExtractor();
// Base max distance threshold on the current road class we're on
const auto &data = node_based_graph.GetEdgeData(onto);
const auto threshold = scaledThresholdByRoadClass(MAX_SLIPROAD_THRESHOLD, // <- scales down
data.road_classification);
DistanceToNextIntersectionAccumulator accumulator{extractor, node_based_graph, threshold};
DistanceToNextIntersectionAccumulator accumulator{
coordinate_extractor, node_based_graph, threshold};
const SkipTrafficSignalBarrierRoadSelector selector{};
(void)graph_walker.TraverseRoad(start, onto, accumulator, selector);