Compare commits
15 Commits
Author | SHA1 | Date | |
---|---|---|---|
|
a0b1a5df8c | ||
|
411313f666 | ||
|
ada0a1e8f8 | ||
|
74611f94fa | ||
|
eaff3b4210 | ||
|
1fb9f3e1eb | ||
|
6ea9f9fdf1 | ||
|
434a3a638a | ||
|
6305f4a529 | ||
|
646b1631ab | ||
|
a852ab1c43 | ||
|
ff25fc70f0 | ||
|
b34ed587d0 | ||
|
b58329104a | ||
|
d188e8e2a8 |
@ -13,6 +13,7 @@ notifications:
|
|||||||
branches:
|
branches:
|
||||||
only:
|
only:
|
||||||
- master
|
- master
|
||||||
|
- 5.5
|
||||||
|
|
||||||
cache:
|
cache:
|
||||||
ccache: true
|
ccache: true
|
||||||
|
19
CHANGELOG.md
19
CHANGELOG.md
@ -1,3 +1,22 @@
|
|||||||
|
# 5.5.3
|
||||||
|
- Changes from 5.5.2
|
||||||
|
- Bugfixes:
|
||||||
|
- PR #3504 - debug tiles were very slow to generate due to unnecessarily copying data in a hot loop.
|
||||||
|
- PR #3556 - fix an assertion in the walking profile triggered by tight spiral stairwells
|
||||||
|
- PR #3469 - don't assert when identical coordinates are supplied to some calculations - OSM data contains these, we shouldn't crash.
|
||||||
|
- Enhancements:
|
||||||
|
- backported 6ea9f9fdf19 - when anticipating upcoming lanes, consider how many lanes need to be crossed to get there.
|
||||||
|
- when using osrm-datastore, it will attempt to clean up locks if it crashes.
|
||||||
|
|
||||||
|
# 5.5.2
|
||||||
|
- Changes from 5.5.1
|
||||||
|
- Revert smarter map-matching search radius. The increased radius causes performance degredation when map-matching against non-car road networks with more edges.
|
||||||
|
|
||||||
|
# 5.5.1
|
||||||
|
- Changes from 5.5.0
|
||||||
|
- Bugfixes
|
||||||
|
- Fixes #3455 where a deadlock could occur if re-loading new data under heavy load with multiple consumers osrm-datastore
|
||||||
|
|
||||||
# 5.5.0
|
# 5.5.0
|
||||||
- Changes from 5.4.0
|
- Changes from 5.4.0
|
||||||
- API:
|
- API:
|
||||||
|
@ -53,7 +53,7 @@ endif()
|
|||||||
project(OSRM C CXX)
|
project(OSRM C CXX)
|
||||||
set(OSRM_VERSION_MAJOR 5)
|
set(OSRM_VERSION_MAJOR 5)
|
||||||
set(OSRM_VERSION_MINOR 5)
|
set(OSRM_VERSION_MINOR 5)
|
||||||
set(OSRM_VERSION_PATCH 0)
|
set(OSRM_VERSION_PATCH 3)
|
||||||
set(OSRM_VERSION "${OSRM_VERSION_MAJOR}.${OSRM_VERSION_MINOR}.${OSRM_VERSION_PATCH}")
|
set(OSRM_VERSION "${OSRM_VERSION_MAJOR}.${OSRM_VERSION_MINOR}.${OSRM_VERSION_PATCH}")
|
||||||
|
|
||||||
add_definitions(-DOSRM_PROJECT_DIR="${CMAKE_CURRENT_SOURCE_DIR}")
|
add_definitions(-DOSRM_PROJECT_DIR="${CMAKE_CURRENT_SOURCE_DIR}")
|
||||||
|
@ -783,3 +783,38 @@ Feature: Turn Lane Guidance
|
|||||||
| waypoints | route | turns | lanes |
|
| waypoints | route | turns | lanes |
|
||||||
| a,f | start,first,second,third,fourth,fourth | depart,turn left,turn left,turn left,turn right,arrive | ,left:false left:true none:false none:false,left:false left:true none:false none:false,left:false left:true none:false none:false,left:false left:false right:true, |
|
| a,f | start,first,second,third,fourth,fourth | depart,turn left,turn left,turn left,turn right,arrive | ,left:false left:true none:false none:false,left:false left:true none:false none:false,left:false left:true none:false none:false,left:false left:false right:true, |
|
||||||
| a,g | start,first,second,third,fourth,fourth | depart,turn left,turn left,turn left,turn left,arrive | ,left:true left:true none:false none:false,left:true left:true none:false none:false,left:true left:true none:false none:false,left:true left:true right:false, |
|
| a,g | start,first,second,third,fourth,fourth | depart,turn left,turn left,turn left,turn left,arrive | ,left:true left:true none:false none:false,left:true left:true none:false none:false,left:true left:true none:false none:false,left:true left:true right:false, |
|
||||||
|
|
||||||
|
@anticipate
|
||||||
|
Scenario: Complex lane scenarios scale threshold for triggering Lane Anticipation
|
||||||
|
Given the node map
|
||||||
|
"""
|
||||||
|
a – b – x
|
||||||
|
|
|
||||||
|
|
|
||||||
|
|
|
||||||
|
|
|
||||||
|
|
|
||||||
|
|
|
||||||
|
|
|
||||||
|
|
|
||||||
|
|
|
||||||
|
|
|
||||||
|
c
|
||||||
|
|
|
||||||
|
e – d – y
|
||||||
|
"""
|
||||||
|
# With a grid size of 20m the duration is ~20s but our default threshold for Lane Anticipation is 15s.
|
||||||
|
# The additional lanes left and right of the turn scale the threshold up so that Lane Anticipation still triggers.
|
||||||
|
|
||||||
|
And the ways
|
||||||
|
| nodes | turn:lanes:forward | name |
|
||||||
|
| ab | through\|through\|right\|right | MySt |
|
||||||
|
| bx | | XSt |
|
||||||
|
| bc | | MySt |
|
||||||
|
| cd | left\|right | MySt |
|
||||||
|
| de | | MySt |
|
||||||
|
| dy | | YSt |
|
||||||
|
|
||||||
|
When I route I should get
|
||||||
|
| waypoints | route | turns | lanes |
|
||||||
|
| a,e | MySt,MySt,MySt,MySt | depart,continue right,turn right,arrive | ,straight:false straight:false right:false right:true,left:false right:true, |
|
||||||
|
@ -1260,3 +1260,60 @@ Feature: Simple Turns
|
|||||||
When I route I should get
|
When I route I should get
|
||||||
| waypoints | route | intersections |
|
| waypoints | route | intersections |
|
||||||
| a,g | ab,bcdefgh,bcdefgh | true:90;true:45 false:180 false:270;true:180 |
|
| a,g | ab,bcdefgh,bcdefgh | true:90;true:45 false:180 false:270;true:180 |
|
||||||
|
|
||||||
|
#https://github.com/Project-OSRM/osrm-backend/pull/3469#issuecomment-270806580
|
||||||
|
Scenario: Oszillating Lower Priority Road
|
||||||
|
#Given the node map
|
||||||
|
# """
|
||||||
|
# a -db c
|
||||||
|
# f
|
||||||
|
# """
|
||||||
|
Given the node locations
|
||||||
|
| node | lat | lon | # |
|
||||||
|
| a | 1.0 | 1.0 | |
|
||||||
|
| b | 1.0000179813587253 | 1.0 | |
|
||||||
|
| c | 1.0000204580571323 | 1.0 | |
|
||||||
|
| d | 1.0000179813587253 | 1.0 | same as b |
|
||||||
|
| f | 1.0000179813587253 | 1.0000179813587253 | |
|
||||||
|
|
||||||
|
And the ways
|
||||||
|
| nodes | oneway | lanes | highway |
|
||||||
|
| ab | yes | 1 | primary |
|
||||||
|
| bf | yes | 1 | primary |
|
||||||
|
| bcd | yes | 1 | service |
|
||||||
|
|
||||||
|
# we don't care for turn instructions, this is a coordinate extraction bug check
|
||||||
|
When I route I should get
|
||||||
|
| waypoints | route |
|
||||||
|
| a,d | ab,ab |
|
||||||
|
|
||||||
|
Scenario: Sharp Turn Onto A Bridge
|
||||||
|
Given the node map
|
||||||
|
"""
|
||||||
|
e
|
||||||
|
|
|
||||||
|
|
|
||||||
|
|
|
||||||
|
|
|
||||||
|
|
|
||||||
|
|
|
||||||
|
|
|
||||||
|
|
|
||||||
|
|
|
||||||
|
|
|
||||||
|
|
|
||||||
|
|
|
||||||
|
|
|
||||||
|
g a - - -b
|
||||||
|
f /
|
||||||
|
d -c
|
||||||
|
"""
|
||||||
|
|
||||||
|
And the ways
|
||||||
|
| nodes | oneway | lanes |
|
||||||
|
| gaf | yes | 1 |
|
||||||
|
| abcde | yes | 1 |
|
||||||
|
|
||||||
|
When I route I should get
|
||||||
|
| waypoints | route |
|
||||||
|
| g,e | abcde,abcde |
|
||||||
|
@ -38,29 +38,33 @@ class SharedMemoryDataFacade : public ContiguousInternalMemoryDataFacadeBase
|
|||||||
// used anymore. We crash hard here if something goes wrong (noexcept).
|
// used anymore. We crash hard here if something goes wrong (noexcept).
|
||||||
virtual ~SharedMemoryDataFacade() noexcept
|
virtual ~SharedMemoryDataFacade() noexcept
|
||||||
{
|
{
|
||||||
|
// Now check if this is still the newest dataset
|
||||||
|
boost::interprocess::sharable_lock<boost::interprocess::named_upgradable_mutex>
|
||||||
|
current_regions_lock(shared_barriers->current_regions_mutex,
|
||||||
|
boost::interprocess::defer_lock);
|
||||||
|
|
||||||
boost::interprocess::scoped_lock<boost::interprocess::named_sharable_mutex> exclusive_lock(
|
boost::interprocess::scoped_lock<boost::interprocess::named_sharable_mutex> exclusive_lock(
|
||||||
data_region == storage::DATA_1 ? shared_barriers->regions_1_mutex
|
data_region == storage::DATA_1 ? shared_barriers->regions_1_mutex
|
||||||
: shared_barriers->regions_2_mutex,
|
: shared_barriers->regions_2_mutex,
|
||||||
boost::interprocess::defer_lock);
|
boost::interprocess::defer_lock);
|
||||||
|
|
||||||
// if this returns false this is still in use
|
// if this returns false this is still in use
|
||||||
if (exclusive_lock.try_lock())
|
if (current_regions_lock.try_lock() && exclusive_lock.try_lock())
|
||||||
{
|
{
|
||||||
if (storage::SharedMemory::RegionExists(data_region))
|
if (storage::SharedMemory::RegionExists(data_region))
|
||||||
{
|
{
|
||||||
BOOST_ASSERT(storage::SharedMemory::RegionExists(layout_region));
|
BOOST_ASSERT(storage::SharedMemory::RegionExists(layout_region));
|
||||||
|
|
||||||
// Now check if this is still the newest dataset
|
|
||||||
const boost::interprocess::sharable_lock<boost::interprocess::named_upgradable_mutex>
|
|
||||||
lock(shared_barriers->current_regions_mutex);
|
|
||||||
|
|
||||||
auto shared_regions = storage::makeSharedMemory(storage::CURRENT_REGIONS);
|
auto shared_regions = storage::makeSharedMemory(storage::CURRENT_REGIONS);
|
||||||
const auto current_timestamp =
|
const auto current_timestamp =
|
||||||
static_cast<const storage::SharedDataTimestamp *>(shared_regions->Ptr());
|
static_cast<const storage::SharedDataTimestamp *>(shared_regions->Ptr());
|
||||||
|
|
||||||
if (current_timestamp->timestamp == shared_timestamp)
|
// check if the memory region referenced by this facade needs cleanup
|
||||||
|
if (current_timestamp->data == data_region)
|
||||||
{
|
{
|
||||||
util::Log(logDEBUG) << "Retaining data with shared timestamp " << shared_timestamp;
|
BOOST_ASSERT(current_timestamp->layout == layout_region);
|
||||||
|
util::Log(logDEBUG) << "Retaining data with shared timestamp "
|
||||||
|
<< shared_timestamp;
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
|
@ -28,7 +28,8 @@ class CoordinateExtractor
|
|||||||
/* Find a interpolated coordinate a long the compressed geometries. The desired coordinate
|
/* Find a interpolated coordinate a long the compressed geometries. The desired coordinate
|
||||||
* should be in a certain distance. This method is dedicated to find representative coordinates
|
* should be in a certain distance. This method is dedicated to find representative coordinates
|
||||||
* at turns.
|
* at turns.
|
||||||
* Since we are computing the length of the segment anyhow, we also return it.
|
* Note: The segment between intersection and turn coordinate can be zero, if the OSM modelling
|
||||||
|
* is unfortunate. See https://github.com/Project-OSRM/osrm-backend/issues/3470
|
||||||
*/
|
*/
|
||||||
OSRM_ATTR_WARN_UNUSED
|
OSRM_ATTR_WARN_UNUSED
|
||||||
util::Coordinate GetCoordinateAlongRoad(const NodeID intersection_node,
|
util::Coordinate GetCoordinateAlongRoad(const NodeID intersection_node,
|
||||||
|
@ -4,6 +4,7 @@
|
|||||||
#include "extractor/guidance/turn_instruction.hpp"
|
#include "extractor/guidance/turn_instruction.hpp"
|
||||||
#include "engine/guidance/post_processing.hpp"
|
#include "engine/guidance/post_processing.hpp"
|
||||||
|
|
||||||
|
#include <algorithm>
|
||||||
#include <iterator>
|
#include <iterator>
|
||||||
#include <unordered_set>
|
#include <unordered_set>
|
||||||
#include <utility>
|
#include <utility>
|
||||||
@ -27,9 +28,38 @@ std::vector<RouteStep> anticipateLaneChange(std::vector<RouteStep> steps,
|
|||||||
{
|
{
|
||||||
// Lane anticipation works on contiguous ranges of quick steps that have lane information
|
// Lane anticipation works on contiguous ranges of quick steps that have lane information
|
||||||
const auto is_quick_has_lanes = [&](const RouteStep &step) {
|
const auto is_quick_has_lanes = [&](const RouteStep &step) {
|
||||||
const auto is_quick = step.duration < min_duration_needed_for_lane_change;
|
|
||||||
const auto has_lanes = step.intersections.front().lanes.lanes_in_turn > 0;
|
const auto has_lanes = step.intersections.front().lanes.lanes_in_turn > 0;
|
||||||
return has_lanes && is_quick;
|
|
||||||
|
if (!has_lanes)
|
||||||
|
return false;
|
||||||
|
|
||||||
|
// The more unused lanes to the left and right of the turn there are, the higher
|
||||||
|
// the chance the user is driving on one of those and has to cross lanes.
|
||||||
|
// Scale threshold for these cases to be adaptive to the situation's complexity.
|
||||||
|
//
|
||||||
|
// Note: what we could do instead: do Lane Anticipation on all step pairs and then scale
|
||||||
|
// the threshold based on the lanes we're constraining the user to. Would need a re-write
|
||||||
|
// since at the moment we first group-by and only then do Lane Anticipation selectively.
|
||||||
|
//
|
||||||
|
// We do not have a source-target lane mapping, assume worst case for lanes to cross.
|
||||||
|
|
||||||
|
// The following two lambda functions are backported from
|
||||||
|
// https://github.com/Project-OSRM/osrm-backend/pull/3474
|
||||||
|
const auto NumLanesToTheRight = [](const RouteStep &step) -> LaneID {
|
||||||
|
return step.intersections.front().lanes.first_lane_from_the_right;
|
||||||
|
};
|
||||||
|
const auto NumLanesToTheLeft = [](const RouteStep &step) -> LaneID {
|
||||||
|
LaneID const total = step.intersections.front().lane_description.size();
|
||||||
|
return total - (step.intersections.front().lanes.lanes_in_turn +
|
||||||
|
step.intersections.front().lanes.first_lane_from_the_right);
|
||||||
|
};
|
||||||
|
|
||||||
|
const auto to_cross = std::max(NumLanesToTheRight(step), NumLanesToTheLeft(step));
|
||||||
|
const auto scale = 1 + to_cross;
|
||||||
|
const auto threshold = scale * min_duration_needed_for_lane_change;
|
||||||
|
|
||||||
|
const auto is_quick = step.duration < threshold;
|
||||||
|
return is_quick;
|
||||||
};
|
};
|
||||||
|
|
||||||
using StepIter = decltype(steps)::iterator;
|
using StepIter = decltype(steps)::iterator;
|
||||||
|
@ -19,14 +19,6 @@
|
|||||||
#include <string>
|
#include <string>
|
||||||
#include <vector>
|
#include <vector>
|
||||||
|
|
||||||
static double search_radius_for_gps_radius(double gps_radius)
|
|
||||||
{
|
|
||||||
// For a given GPS radius, determine the radius we need to search for candidate street segments
|
|
||||||
// to have a 99.9% chance of finding the correct segment.
|
|
||||||
// For more detail, see the analysis at https://github.com/Project-OSRM/osrm-backend/pull/3184
|
|
||||||
return std::min(gps_radius * 3.5 + 45, 200.0);
|
|
||||||
}
|
|
||||||
|
|
||||||
namespace osrm
|
namespace osrm
|
||||||
{
|
{
|
||||||
namespace engine
|
namespace engine
|
||||||
@ -160,9 +152,16 @@ Status MatchPlugin::HandleRequest(const std::shared_ptr<datafacade::BaseDataFaca
|
|||||||
std::transform(parameters.radiuses.begin(),
|
std::transform(parameters.radiuses.begin(),
|
||||||
parameters.radiuses.end(),
|
parameters.radiuses.end(),
|
||||||
search_radiuses.begin(),
|
search_radiuses.begin(),
|
||||||
[&](const boost::optional<double> &maybe_radius) {
|
[](const boost::optional<double> &maybe_radius) {
|
||||||
double gps_radius = maybe_radius ? *maybe_radius : DEFAULT_GPS_PRECISION;
|
if (maybe_radius)
|
||||||
return search_radius_for_gps_radius(gps_radius);
|
{
|
||||||
|
return *maybe_radius * RADIUS_MULTIPLIER;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
return DEFAULT_GPS_PRECISION * RADIUS_MULTIPLIER;
|
||||||
|
}
|
||||||
|
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -370,7 +370,7 @@ Status TilePlugin::HandleRequest(const std::shared_ptr<datafacade::BaseDataFacad
|
|||||||
// as the sort condition
|
// as the sort condition
|
||||||
std::sort(sorted_edge_indexes.begin(),
|
std::sort(sorted_edge_indexes.begin(),
|
||||||
sorted_edge_indexes.end(),
|
sorted_edge_indexes.end(),
|
||||||
[edges](const std::size_t &left, const std::size_t &right) -> bool {
|
[&edges](const std::size_t &left, const std::size_t &right) -> bool {
|
||||||
return (edges[left].u != edges[right].u) ? edges[left].u < edges[right].u
|
return (edges[left].u != edges[right].u) ? edges[left].u < edges[right].u
|
||||||
: edges[left].v < edges[right].v;
|
: edges[left].v < edges[right].v;
|
||||||
});
|
});
|
||||||
|
@ -94,23 +94,21 @@ util::Coordinate CoordinateExtractor::ExtractRepresentativeCoordinate(
|
|||||||
const std::uint8_t intersection_lanes,
|
const std::uint8_t intersection_lanes,
|
||||||
std::vector<util::Coordinate> coordinates) const
|
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
|
return util::Coordinate(traversed_in_reverse
|
||||||
? node_coordinates[to_node]
|
? node_coordinates[to_node]
|
||||||
: node_coordinates[intersection_node]) != coordinate;
|
: node_coordinates[intersection_node]) != coordinate;
|
||||||
};
|
};
|
||||||
// this is only used for debug purposes in assertions. We don't want warnings about it
|
// this is only used for debug purposes in assertions. We don't want warnings about it
|
||||||
(void)is_valid_result;
|
(void)not_same_as_start;
|
||||||
|
|
||||||
// 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);
|
|
||||||
|
|
||||||
// Fallback. These roads are small broken self-loops that shouldn't be in the data at all
|
// Fallback. These roads are small broken self-loops that shouldn't be in the data at all
|
||||||
if (intersection_node == to_node)
|
if (intersection_node == to_node)
|
||||||
|
{
|
||||||
|
BOOST_ASSERT(coordinates.size() >= 2);
|
||||||
return coordinates[1];
|
return coordinates[1];
|
||||||
|
}
|
||||||
|
|
||||||
/* if we are looking at a straight line, we don't care where exactly the coordinate
|
/* 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
|
* is. Simply return the final coordinate. Turn angles/turn vectors are the same no matter which
|
||||||
@ -118,8 +116,8 @@ util::Coordinate CoordinateExtractor::ExtractRepresentativeCoordinate(
|
|||||||
*/
|
*/
|
||||||
if (coordinates.size() <= 2)
|
if (coordinates.size() <= 2)
|
||||||
{
|
{
|
||||||
// Here we can't check for validity, due to possible dead-ends with repeated coordinates
|
// TODO: possibly re-enable with https://github.com/Project-OSRM/osrm-backend/issues/3470
|
||||||
// BOOST_ASSERT(is_valid_result(coordinates.back()));
|
// BOOST_ASSERT(not_same_as_start(result));
|
||||||
return coordinates.back();
|
return coordinates.back();
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -130,25 +128,20 @@ util::Coordinate CoordinateExtractor::ExtractRepresentativeCoordinate(
|
|||||||
// fallback, mostly necessary for dead ends
|
// fallback, mostly necessary for dead ends
|
||||||
if (intersection_node == to_node)
|
if (intersection_node == to_node)
|
||||||
{
|
{
|
||||||
const auto result = ExtractCoordinateAtLength(
|
const auto result = ExtractCoordinateAtLength(skipping_inaccuracies_distance, coordinates);
|
||||||
skipping_inaccuracies_distance, coordinates);
|
// TODO: possibly re-enable with https://github.com/Project-OSRM/osrm-backend/issues/3470
|
||||||
BOOST_ASSERT(is_valid_result(result));
|
// BOOST_ASSERT(not_same_as_start(result));
|
||||||
return 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);
|
const auto &turn_edge_data = node_based_graph.GetEdgeData(turn_edge);
|
||||||
|
|
||||||
// roundabouts, check early to avoid other costly checks
|
// roundabouts, check early to avoid other costly checks
|
||||||
if (turn_edge_data.roundabout || turn_edge_data.circular)
|
if (turn_edge_data.roundabout || turn_edge_data.circular)
|
||||||
{
|
{
|
||||||
const auto result = ExtractCoordinateAtLength(
|
const auto result = ExtractCoordinateAtLength(skipping_inaccuracies_distance, coordinates);
|
||||||
skipping_inaccuracies_distance, coordinates);
|
// TODO: possibly re-enable with https://github.com/Project-OSRM/osrm-backend/issues/3470
|
||||||
BOOST_ASSERT(is_valid_result(result));
|
// BOOST_ASSERT(not_same_as_start(result));
|
||||||
return result;
|
return result;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -169,21 +162,34 @@ util::Coordinate CoordinateExtractor::ExtractRepresentativeCoordinate(
|
|||||||
util::coordinate_calculation::haversineDistance(turn_coordinate, coordinates[1]) <
|
util::coordinate_calculation::haversineDistance(turn_coordinate, coordinates[1]) <
|
||||||
ASSUMED_LANE_WIDTH)
|
ASSUMED_LANE_WIDTH)
|
||||||
{
|
{
|
||||||
const auto result =
|
const auto initial_distance =
|
||||||
GetCorrectedCoordinate(turn_coordinate, coordinates[1], coordinates.back());
|
util::coordinate_calculation::haversineDistance(turn_coordinate, coordinates[1]);
|
||||||
BOOST_ASSERT(is_valid_result(result));
|
const auto total_distance = util::coordinate_calculation::haversineDistance(
|
||||||
return result;
|
turn_coordinate, coordinates.back());
|
||||||
}
|
|
||||||
else
|
if (initial_distance > ASSUMED_LANE_WIDTH && total_distance > initial_distance)
|
||||||
{
|
{
|
||||||
BOOST_ASSERT(is_valid_result(coordinates.back()));
|
const auto result =
|
||||||
return coordinates.back();
|
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 =
|
const auto first_distance =
|
||||||
util::coordinate_calculation::haversineDistance(coordinates[0], coordinates[1]);
|
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
|
/* 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
|
* 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
|
* information on the very first turn angle (requires knowledge about previous road) and the
|
||||||
@ -197,7 +203,7 @@ util::Coordinate CoordinateExtractor::ExtractRepresentativeCoordinate(
|
|||||||
|
|
||||||
if (first_coordinate_is_far_away)
|
if (first_coordinate_is_far_away)
|
||||||
{
|
{
|
||||||
BOOST_ASSERT(is_valid_result(coordinates[1]));
|
BOOST_ASSERT(not_same_as_start(coordinates[1]));
|
||||||
return coordinates[1];
|
return coordinates[1];
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -237,7 +243,8 @@ util::Coordinate CoordinateExtractor::ExtractRepresentativeCoordinate(
|
|||||||
if (coordinates.size() == 2 ||
|
if (coordinates.size() == 2 ||
|
||||||
total_distance <= skipping_inaccuracies_distance)
|
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();
|
return coordinates.back();
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -252,14 +259,14 @@ util::Coordinate CoordinateExtractor::ExtractRepresentativeCoordinate(
|
|||||||
// As a back-up, we have to check for this case
|
// As a back-up, we have to check for this case
|
||||||
if (coordinates.front() == coordinates.back())
|
if (coordinates.front() == coordinates.back())
|
||||||
{
|
{
|
||||||
const auto result = ExtractCoordinateAtLength(
|
const auto result =
|
||||||
skipping_inaccuracies_distance, coordinates);
|
ExtractCoordinateAtLength(skipping_inaccuracies_distance, coordinates);
|
||||||
BOOST_ASSERT(is_valid_result(result));
|
BOOST_ASSERT(not_same_as_start(result));
|
||||||
return result;
|
return result;
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
BOOST_ASSERT(is_valid_result(coordinates.back()));
|
BOOST_ASSERT(not_same_as_start(coordinates.back()));
|
||||||
return coordinates.back();
|
return coordinates.back();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -299,7 +306,7 @@ util::Coordinate CoordinateExtractor::ExtractRepresentativeCoordinate(
|
|||||||
{
|
{
|
||||||
// skip over repeated coordinates
|
// skip over repeated coordinates
|
||||||
const auto result = ExtractCoordinateAtLength(5, coordinates, segment_distances);
|
const auto result = ExtractCoordinateAtLength(5, coordinates, segment_distances);
|
||||||
BOOST_ASSERT(is_valid_result(result));
|
BOOST_ASSERT(not_same_as_start(result));
|
||||||
return result;
|
return result;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -333,7 +340,7 @@ util::Coordinate CoordinateExtractor::ExtractRepresentativeCoordinate(
|
|||||||
.second;
|
.second;
|
||||||
const auto result =
|
const auto result =
|
||||||
GetCorrectedCoordinate(turn_coordinate, coord_between_front, coord_between_back);
|
GetCorrectedCoordinate(turn_coordinate, coord_between_front, coord_between_back);
|
||||||
BOOST_ASSERT(is_valid_result(result));
|
BOOST_ASSERT(not_same_as_start(result));
|
||||||
return result;
|
return result;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -354,7 +361,7 @@ util::Coordinate CoordinateExtractor::ExtractRepresentativeCoordinate(
|
|||||||
const auto result = GetCorrectedCoordinate(
|
const auto result = GetCorrectedCoordinate(
|
||||||
turn_coordinate, coordinates[offset_index], coordinates[offset_index + 1]);
|
turn_coordinate, coordinates[offset_index], coordinates[offset_index + 1]);
|
||||||
|
|
||||||
BOOST_ASSERT(is_valid_result(result));
|
BOOST_ASSERT(not_same_as_start(result));
|
||||||
return result;
|
return result;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -388,7 +395,7 @@ util::Coordinate CoordinateExtractor::ExtractRepresentativeCoordinate(
|
|||||||
BOOST_ASSERT(coordinates.size() >= 2);
|
BOOST_ASSERT(coordinates.size() >= 2);
|
||||||
const auto result =
|
const auto result =
|
||||||
GetCorrectedCoordinate(turn_coordinate, coordinates.back(), vector_head);
|
GetCorrectedCoordinate(turn_coordinate, coordinates.back(), vector_head);
|
||||||
BOOST_ASSERT(is_valid_result(result));
|
BOOST_ASSERT(not_same_as_start(result));
|
||||||
return result;
|
return result;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -414,18 +421,30 @@ util::Coordinate CoordinateExtractor::ExtractRepresentativeCoordinate(
|
|||||||
{
|
{
|
||||||
const auto result = GetCorrectedCoordinate(
|
const auto result = GetCorrectedCoordinate(
|
||||||
turn_coordinate, regression_line_trimmed.first, regression_line_trimmed.second);
|
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;
|
return result;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// We use the locations on the regression line to offset the regression line onto the
|
|
||||||
// intersection.
|
|
||||||
const auto result =
|
const auto result =
|
||||||
ExtractCoordinateAtLength(LOOKAHEAD_DISTANCE_WITHOUT_LANES, coordinates, segment_distances);
|
ExtractCoordinateAtLength(LOOKAHEAD_DISTANCE_WITHOUT_LANES, coordinates, segment_distances);
|
||||||
BOOST_ASSERT(is_valid_result(result));
|
// there are cases that loop back to the original node (e.g. a tiny circle travelling on steps).
|
||||||
return result;
|
// To compensate for these, we check if we got back to the start and, if so, return the first
|
||||||
|
// valid result
|
||||||
|
if (not_same_as_start(result))
|
||||||
|
{
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
const auto result_itr =
|
||||||
|
std::find_if(coordinates.begin(), coordinates.end(), not_same_as_start);
|
||||||
|
if (result_itr != coordinates.end())
|
||||||
|
return *result_itr;
|
||||||
|
else
|
||||||
|
return result;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
util::Coordinate
|
util::Coordinate
|
||||||
@ -989,7 +1008,9 @@ CoordinateExtractor::GetCorrectedCoordinate(const util::Coordinate fixpoint,
|
|||||||
// we can use the end-coordinate
|
// we can use the end-coordinate
|
||||||
if (util::coordinate_calculation::haversineDistance(vector_base, vector_head) <
|
if (util::coordinate_calculation::haversineDistance(vector_base, vector_head) <
|
||||||
DESIRED_COORDINATE_DIFFERENCE)
|
DESIRED_COORDINATE_DIFFERENCE)
|
||||||
|
{
|
||||||
return vector_head;
|
return vector_head;
|
||||||
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
/* to correct for the initial offset, we move the lookahead coordinate close
|
/* to correct for the initial offset, we move the lookahead coordinate close
|
||||||
|
@ -2,8 +2,10 @@
|
|||||||
|
|
||||||
#include "util/bearing.hpp"
|
#include "util/bearing.hpp"
|
||||||
#include "util/coordinate_calculation.hpp"
|
#include "util/coordinate_calculation.hpp"
|
||||||
|
#include "util/log.hpp"
|
||||||
|
|
||||||
#include <algorithm>
|
#include <algorithm>
|
||||||
|
#include <cmath>
|
||||||
#include <functional> // mem_fn
|
#include <functional> // mem_fn
|
||||||
#include <limits>
|
#include <limits>
|
||||||
#include <numeric>
|
#include <numeric>
|
||||||
@ -101,6 +103,19 @@ IntersectionGenerator::ComputeIntersectionShape(const NodeID node_at_center_of_i
|
|||||||
bearing =
|
bearing =
|
||||||
util::coordinate_calculation::bearing(turn_coordinate, coordinate_along_edge_leaving);
|
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});
|
intersection.push_back({edge_connected_to_intersection, bearing, segment_length});
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -204,6 +204,20 @@ bool RoundaboutHandler::qualifiesAsRoundaboutIntersection(
|
|||||||
|
|
||||||
result.push_back(
|
result.push_back(
|
||||||
util::coordinate_calculation::bearing(src_coordinate, next_coordinate));
|
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;
|
break;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -301,12 +301,18 @@ operator()(const NodeID /*nid*/, const EdgeID source_edge_id, Intersection inter
|
|||||||
//
|
//
|
||||||
// Sliproad Not a Sliproad
|
// 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 NodeID start = intersection_node_id; // b
|
||||||
const EdgeID edge = sliproad_edge; // bd
|
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);
|
BOOST_ASSERT(coords.size() >= 2);
|
||||||
|
|
||||||
// Now keep start and end coordinate fix and check for curvature
|
// Now keep start and end coordinate fix and check for curvature
|
||||||
@ -544,14 +550,15 @@ bool SliproadHandler::nextIntersectionIsTooFarAway(const NodeID start, const Edg
|
|||||||
BOOST_ASSERT(start != SPECIAL_NODEID);
|
BOOST_ASSERT(start != SPECIAL_NODEID);
|
||||||
BOOST_ASSERT(onto != SPECIAL_EDGEID);
|
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
|
// Base max distance threshold on the current road class we're on
|
||||||
const auto &data = node_based_graph.GetEdgeData(onto);
|
const auto &data = node_based_graph.GetEdgeData(onto);
|
||||||
const auto threshold = scaledThresholdByRoadClass(MAX_SLIPROAD_THRESHOLD, // <- scales down
|
const auto threshold = scaledThresholdByRoadClass(MAX_SLIPROAD_THRESHOLD, // <- scales down
|
||||||
data.road_classification);
|
data.road_classification);
|
||||||
|
|
||||||
DistanceToNextIntersectionAccumulator accumulator{extractor, node_based_graph, threshold};
|
DistanceToNextIntersectionAccumulator accumulator{
|
||||||
|
coordinate_extractor, node_based_graph, threshold};
|
||||||
const SkipTrafficSignalBarrierRoadSelector selector{};
|
const SkipTrafficSignalBarrierRoadSelector selector{};
|
||||||
|
|
||||||
(void)graph_walker.TraverseRoad(start, onto, accumulator, selector);
|
(void)graph_walker.TraverseRoad(start, onto, accumulator, selector);
|
||||||
|
@ -1,3 +1,4 @@
|
|||||||
|
#include "storage/shared_barriers.hpp"
|
||||||
#include "storage/storage.hpp"
|
#include "storage/storage.hpp"
|
||||||
#include "util/exception.hpp"
|
#include "util/exception.hpp"
|
||||||
#include "util/log.hpp"
|
#include "util/log.hpp"
|
||||||
@ -7,6 +8,9 @@
|
|||||||
#include <boost/filesystem.hpp>
|
#include <boost/filesystem.hpp>
|
||||||
#include <boost/program_options.hpp>
|
#include <boost/program_options.hpp>
|
||||||
|
|
||||||
|
#include <csignal>
|
||||||
|
#include <cstdlib>
|
||||||
|
|
||||||
using namespace osrm;
|
using namespace osrm;
|
||||||
|
|
||||||
// generate boost::program_options object for the routing part
|
// generate boost::program_options object for the routing part
|
||||||
@ -87,8 +91,20 @@ bool generateDataStoreOptions(const int argc,
|
|||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
[[ noreturn ]] void CleanupSharedBarriers(int signum)
|
||||||
|
{ // Here the lock state of named mutexes is unknown, make a hard cleanup
|
||||||
|
osrm::storage::SharedBarriers::resetCurrentRegions();
|
||||||
|
std::_Exit(128 + signum);
|
||||||
|
}
|
||||||
|
|
||||||
int main(const int argc, const char *argv[]) try
|
int main(const int argc, const char *argv[]) try
|
||||||
{
|
{
|
||||||
|
int signals[] = {SIGTERM, SIGSEGV, SIGINT, SIGILL, SIGABRT, SIGFPE};
|
||||||
|
for (auto sig : signals)
|
||||||
|
{
|
||||||
|
std::signal(sig, CleanupSharedBarriers);
|
||||||
|
}
|
||||||
|
|
||||||
util::LogPolicy::GetInstance().Unmute();
|
util::LogPolicy::GetInstance().Unmute();
|
||||||
|
|
||||||
boost::filesystem::path base_path;
|
boost::filesystem::path base_path;
|
||||||
@ -135,4 +151,4 @@ catch (const std::bad_alloc &e)
|
|||||||
util::Log(logERROR) << "Please provide more memory or disable locking the virtual "
|
util::Log(logERROR) << "Please provide more memory or disable locking the virtual "
|
||||||
"address space (note: this makes OSRM swap, i.e. slow)";
|
"address space (note: this makes OSRM swap, i.e. slow)";
|
||||||
return EXIT_FAILURE;
|
return EXIT_FAILURE;
|
||||||
}
|
}
|
||||||
|
@ -152,6 +152,11 @@ double bearing(const Coordinate first_coordinate, const Coordinate second_coordi
|
|||||||
{
|
{
|
||||||
result -= 360.0;
|
result -= 360.0;
|
||||||
}
|
}
|
||||||
|
// If someone gives us two identical coordinates, then the concept of a bearing
|
||||||
|
// makes no sense. However, because it sometimes happens, we'll at least
|
||||||
|
// return a consistent value of 0 so that the behaviour isn't random.
|
||||||
|
BOOST_ASSERT(first_coordinate != second_coordinate || result == 0.);
|
||||||
|
|
||||||
return result;
|
return result;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -32,7 +32,7 @@ BOOST_AUTO_TEST_CASE(test_tile)
|
|||||||
const auto rc = osrm.Tile(params, result);
|
const auto rc = osrm.Tile(params, result);
|
||||||
BOOST_CHECK(rc == Status::Ok);
|
BOOST_CHECK(rc == Status::Ok);
|
||||||
|
|
||||||
BOOST_CHECK_EQUAL(result.size(), 114091);
|
BOOST_CHECK_EQUAL(result.size(), 114098);
|
||||||
|
|
||||||
protozero::pbf_reader tile_message(result);
|
protozero::pbf_reader tile_message(result);
|
||||||
tile_message.next();
|
tile_message.next();
|
||||||
|
@ -311,4 +311,15 @@ BOOST_AUTO_TEST_CASE(circleCenter)
|
|||||||
BOOST_CHECK(!result);
|
BOOST_CHECK(!result);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
BOOST_AUTO_TEST_CASE(consistent_invalid_bearing_result)
|
||||||
|
{
|
||||||
|
const auto pos1 = Coordinate(util::FloatLongitude{0.}, util::FloatLatitude{0.});
|
||||||
|
const auto pos2 = Coordinate(util::FloatLongitude{5.}, util::FloatLatitude{5.});
|
||||||
|
const auto pos3 = Coordinate(util::FloatLongitude{-5.}, util::FloatLatitude{-5.});
|
||||||
|
|
||||||
|
BOOST_CHECK_EQUAL(0., util::coordinate_calculation::bearing(pos1, pos1));
|
||||||
|
BOOST_CHECK_EQUAL(0., util::coordinate_calculation::bearing(pos2, pos2));
|
||||||
|
BOOST_CHECK_EQUAL(0., util::coordinate_calculation::bearing(pos3, pos3));
|
||||||
|
}
|
||||||
|
|
||||||
BOOST_AUTO_TEST_SUITE_END()
|
BOOST_AUTO_TEST_SUITE_END()
|
||||||
|
Loading…
Reference in New Issue
Block a user