Compare commits

...

23 Commits

Author SHA1 Message Date
Daniel Patterson
54ab5373cf Fix tests - backported changes need old namespace. 2017-01-18 22:58:43 -08:00
Daniel Patterson
57bd2cda0f Update changelog and version for 5.5.4 2017-01-18 22:25:20 -08:00
Moritz Kobitzsch
bfbdd18834 fix emitting invalid turn types, now surfacing due to changes in obvious detection
Conflicts:
	features/guidance/dedicated-turn-roads.feature
	include/extractor/guidance/intersection.hpp
2017-01-18 17:22:14 +01:00
Daniel J. Hofmann
5159d57201 Changelog Item for #3561 2017-01-17 12:54:38 +01:00
Michael Krasnyk
bc38275146 Added missing backward_speed for cycleways 2017-01-17 12:53:08 +01:00
Moritz Kobitzsch
c77add50e2 cherry-pick https://github.com/Project-OSRM/osrm-backend/pull/3555 2017-01-17 10:27:33 +01:00
Michael Krasnyk
37e36fd165 Fix possible division by zero by clamping latitude to 85.05°
Resolves #3530
2017-01-17 10:08:27 +01:00
Michael Krasnyk
341109a8f4 Adjusted number of nodes in annotation, resolves #3515
Conflicts:
	CHANGELOG.md
2017-01-17 10:02:07 +01:00
Daniel Patterson
a0b1a5df8c Update version and CHANGELOG for 5.5.3. 2017-01-11 17:14:18 -08:00
Daniel Patterson
411313f666 Backport NumLanesToTheRight/NumLanesToTheLeft to support 6ea9f9fdf1 2017-01-11 16:44:25 -08:00
Moritz Kobitzsch
ada0a1e8f8
fix coordinate assertion for walking profile with steps 2017-01-11 21:57:11 +00:00
Moritz Kobitzsch
74611f94fa
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.
2017-01-11 21:55:29 +00:00
Michael Krasnyk
eaff3b4210
Make a hard reset of named barrier mutexes on signal 2017-01-11 21:43:01 +00:00
Jihyun Yu
1fb9f3e1eb
Fix copying vector on std::sort comparator (#3504) 2017-01-11 21:41:17 +00:00
Daniel J. Hofmann
6ea9f9fdf1
Consider number of lanes to cross, resolves #3025.
Lane Anticipation currently triggers on quick steps with lanes. This
changeset makes the "quick" part more dynamic by taking lanes left and
right of the turn into account. The reasoning for this is as follows.

The user can drive on the leftmost or rightmost lane and has to cross
all lanes left or right of the turn, respecitvely.

We scale our threshold appropriately, which now means the threshold
describes the duration the user needs for crossing _a single lane_.

Note: this is a heuristic and assumes the worst case. Which in my
opinion is fine to do since triggering Lane Anticipation in complex
scenarios is desirable.
2017-01-11 21:37:17 +00:00
Daniel Patterson
434a3a638a Make Travis buildit. 2016-12-21 15:31:03 -08:00
Daniel Patterson
6305f4a529 Update changelog and version. 2016-12-21 15:18:30 -08:00
Patrick Niklaus
646b1631ab Revert "Smarter search radius formula for map matching"
This reverts commit b73c59088c.
2016-12-21 15:14:33 -08:00
Patrick Niklaus
a852ab1c43 Revert "Fix capture"
This reverts commit 4f81e31d63.
2016-12-21 15:14:33 -08:00
Patrick Niklaus
ff25fc70f0 Revert "Hardcode search radius parameters"
This reverts commit 2c9e18d5a9.
2016-12-21 15:14:33 -08:00
Patrick Niklaus
b34ed587d0 Revert "Fix call to std::min"
This reverts commit 8bb183bc8c.
2016-12-21 15:14:33 -08:00
Daniel Patterson
b58329104a Bump version field and update CHANGELOG. 2016-12-16 13:58:21 -08:00
Patrick Niklaus
d188e8e2a8 Fix changing shared memory in multi-process setup (#3462)
This change fixes two bugs:

1. A dead-lock that occurs between osrm-datastore and libosrm when an
   old dataset is free during a data update. This happened because the
   mutexes where acquired in a different order.

2. A region is deleted eventhough it is still in use. This happens when
   libosrm gets overtaken by osrm-datastore, so the new dataset is in
   the same region the old one was.
2016-12-16 13:54:57 -08:00
28 changed files with 511 additions and 116 deletions

View File

@ -13,6 +13,7 @@ notifications:
branches:
only:
- master
- 5.5
cache:
ccache: true

View File

@ -1,3 +1,31 @@
# 5.5.4
- Changes from 5.5.3
- Bugfixes
- PR #3561 - added missing backwards speeds for cycleways in bicycle profile
- PR #3515 - adjusted number of `nodes` in `annotation`
- Ticket #3430 - Fix possible division by zero by clamping latitude to +/- 85.05
- PR #3555 - Fix an error that occurs when a road forks immediately after exiting a ferry
- PR #3575 - Don't emit invalid turn types for obvious turns at sliproads and roundabouts.
# 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
- Changes from 5.4.0
- API:
@ -377,5 +405,3 @@
- `properties.use_turn_restrictions`
- `properties.u_turn_penalty`
- `properties.allow_u_turn_at_via`

View File

@ -53,7 +53,7 @@ endif()
project(OSRM C CXX)
set(OSRM_VERSION_MAJOR 5)
set(OSRM_VERSION_MINOR 5)
set(OSRM_VERSION_PATCH 0)
set(OSRM_VERSION_PATCH 4)
set(OSRM_VERSION "${OSRM_VERSION_MAJOR}.${OSRM_VERSION_MINOR}.${OSRM_VERSION_PATCH}")
add_definitions(-DOSRM_PROJECT_DIR="${CMAKE_CURRENT_SOURCE_DIR}")

View File

@ -783,3 +783,38 @@ Feature: Turn Lane Guidance
| 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,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, |

View File

@ -782,3 +782,40 @@ Feature: Slipways and Dedicated Turn Lanes
When I route I should get
| waypoints | route | turns |
| s,g | main,sliproad,another,another | depart,turn right,turn left,arrive |
Scenario: Sliproad before a roundabout
Given the node map
"""
e
a - b - - c - d
'f|l'
m
g
|
.h-_
k - i |
'.j.'
"""
And the ways
| nodes | junction | oneway | highway | name |
| ab | | yes | primary | road |
| bc | | yes | primary | road |
| cd | | yes | primary | road |
| ec | | yes | secondary | |
| cm | | yes | secondary | |
| mg | | yes | primary | |
| gh | | no | primary | |
| hijh | roundabout | yes | primary | |
| ik | | yes | primary | |
| bfm | | yes | primary | |
| gld | | yes | primary | |
And the relations
| type | way:from | way:to | node:via | restriction |
| restriction | bc | cd | c | only_straight |
When I route I should get
| waypoints | route | turns | locations |
| a,k | road,,, | depart,continue right,roundabout turn right exit-1,arrive | a,b,h,k |

View File

@ -1260,3 +1260,60 @@ Feature: Simple Turns
When I route I should get
| waypoints | route | intersections |
| 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 |

View File

@ -38,29 +38,33 @@ class SharedMemoryDataFacade : public ContiguousInternalMemoryDataFacadeBase
// used anymore. We crash hard here if something goes wrong (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(
data_region == storage::DATA_1 ? shared_barriers->regions_1_mutex
: shared_barriers->regions_2_mutex,
boost::interprocess::defer_lock);
// 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))
{
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);
const auto current_timestamp =
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
{

View File

@ -28,7 +28,8 @@ class CoordinateExtractor
/* 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
* 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
util::Coordinate GetCoordinateAlongRoad(const NodeID intersection_node,

View File

@ -34,6 +34,14 @@ struct IntersectionShapeData
};
inline auto makeCompareShapeDataByBearing(const double base_bearing)
{
return [base_bearing](const auto &lhs, const auto &rhs) {
return util::angularDeviation(base_bearing, lhs.bearing) <
util::angularDeviation(base_bearing, rhs.bearing);
};
}
inline auto makeCompareShapeDataAngleToBearing(const double base_bearing)
{
return [base_bearing](const auto &lhs, const auto &rhs) {
return util::angleBetweenBearings(base_bearing, lhs.bearing) <

View File

@ -29,6 +29,7 @@ inline void print(const engine::guidance::RouteStep &step)
<< " "
<< " Duration: " << step.duration << " Distance: " << step.distance
<< " Geometry: " << step.geometry_begin << " " << step.geometry_end
<< " Exit: " << step.maneuver.exit << " Mode: " << (int)step.mode
<< "\n\tIntersections: " << step.intersections.size() << " [";
for (const auto &intersection : step.intersections)

View File

@ -20,7 +20,7 @@ const constexpr double EARTH_RADIUS_WGS84 = 6378137.0;
// earth circumference devided by 2
const constexpr double MAXEXTENT = EARTH_RADIUS_WGS84 * boost::math::constants::pi<double>();
// ^ math functions are not constexpr since they have side-effects (setting errno) :(
const constexpr double MAX_LATITUDE = 85.;
const constexpr double EPSG3857_MAX_LATITUDE = 85.051128779806592378; // 90(4*atan(exp(pi))/pi-1)
const constexpr double MAX_LONGITUDE = 180.0;
}
@ -29,6 +29,18 @@ const constexpr double DEGREE_TO_PX = detail::MAXEXTENT / 180.0;
// This is the global default tile size for all Mapbox Vector Tiles
const constexpr double TILE_SIZE = 256.0;
inline FloatLatitude clamp(const FloatLatitude lat)
{
return std::max(std::min(lat, FloatLatitude{detail::EPSG3857_MAX_LATITUDE}),
FloatLatitude{-detail::EPSG3857_MAX_LATITUDE});
}
inline FloatLongitude clamp(const FloatLongitude lon)
{
return std::max(std::min(lon, FloatLongitude{detail::MAX_LONGITUDE}),
FloatLongitude{-detail::MAX_LONGITUDE});
}
inline FloatLatitude yToLat(const double y)
{
const auto clamped_y = std::max(-180., std::min(180., y));
@ -41,10 +53,9 @@ inline FloatLatitude yToLat(const double y)
inline double latToY(const FloatLatitude latitude)
{
// apparently this is the (faster) version of the canonical log(tan()) version
const double f = std::sin(detail::DEGREE_TO_RAD * static_cast<double>(latitude));
const double y = detail::RAD_TO_DEGREE * 0.5 * std::log((1 + f) / (1 - f));
const auto clamped_y = std::max(-180., std::min(180., y));
return clamped_y;
const auto clamped_latitude = clamp(latitude);
const double f = std::sin(detail::DEGREE_TO_RAD * static_cast<double>(clamped_latitude));
return detail::RAD_TO_DEGREE * 0.5 * std::log((1 + f) / (1 - f));
}
template <typename T> constexpr double horner(double, T an) { return an; }
@ -91,18 +102,6 @@ inline double latToYapprox(const FloatLatitude latitude)
-3.23083224835967391884404730e-28);
}
inline FloatLatitude clamp(const FloatLatitude lat)
{
return std::max(std::min(lat, FloatLatitude{detail::MAX_LATITUDE}),
FloatLatitude{-detail::MAX_LATITUDE});
}
inline FloatLongitude clamp(const FloatLongitude lon)
{
return std::max(std::min(lon, FloatLongitude{detail::MAX_LONGITUDE}),
FloatLongitude{-detail::MAX_LONGITUDE});
}
inline void pixelToDegree(const double shift, double &x, double &y)
{
const double b = shift / 2.0;
@ -166,9 +165,9 @@ inline void xyzToMercator(
xyzToWGS84(x, y, z, minx, miny, maxx, maxy);
minx = static_cast<double>(clamp(util::FloatLongitude{minx})) * DEGREE_TO_PX;
miny = latToY(clamp(util::FloatLatitude{miny})) * DEGREE_TO_PX;
miny = latToY(util::FloatLatitude{miny}) * DEGREE_TO_PX;
maxx = static_cast<double>(clamp(util::FloatLongitude{maxx})) * DEGREE_TO_PX;
maxy = latToY(clamp(util::FloatLatitude{maxy})) * DEGREE_TO_PX;
maxy = latToY(util::FloatLatitude{maxy}) * DEGREE_TO_PX;
}
}
}

View File

@ -368,10 +368,13 @@ function way_function (way, result)
-- cycleways
if cycleway and cycleway_tags[cycleway] then
result.forward_speed = bicycle_speeds["cycleway"]
result.backward_speed = bicycle_speeds["cycleway"]
elseif cycleway_left and cycleway_tags[cycleway_left] then
result.forward_speed = bicycle_speeds["cycleway"]
result.backward_speed = bicycle_speeds["cycleway"]
elseif cycleway_right and cycleway_tags[cycleway_right] then
result.forward_speed = bicycle_speeds["cycleway"]
result.backward_speed = bicycle_speeds["cycleway"]
end
-- dismount

View File

@ -4,6 +4,7 @@
#include "extractor/guidance/turn_instruction.hpp"
#include "engine/guidance/post_processing.hpp"
#include <algorithm>
#include <iterator>
#include <unordered_set>
#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
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;
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;

View File

@ -1073,7 +1073,8 @@ std::vector<RouteStep> collapseTurns(std::vector<RouteStep> steps)
if (one_back_step.maneuver.instruction.type == TurnType::Sliproad)
{
if (current_step.maneuver.instruction.type == TurnType::Suppressed &&
compatible(one_back_step, current_step))
compatible(one_back_step, current_step) && current_step.intersections.size() == 1 &&
current_step.intersections.front().entry.size() == 2)
{
// Traffic light on the sliproad, the road itself will be handled in the next
// iteration, when one-back-index again points to the sliproad.
@ -1441,6 +1442,7 @@ void trimShortSegments(std::vector<RouteStep> &steps, LegGeometry &geometry)
// This can happen if the last coordinate snaps to a node in the unpacked geometry
geometry.locations.pop_back();
geometry.annotations.pop_back();
geometry.osm_node_ids.pop_back();
geometry.segment_offsets.back()--;
// since the last geometry includes the location of arrival, the arrival instruction
// geometry overlaps with the previous segment

View File

@ -19,14 +19,6 @@
#include <string>
#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 engine
@ -160,9 +152,16 @@ Status MatchPlugin::HandleRequest(const std::shared_ptr<datafacade::BaseDataFaca
std::transform(parameters.radiuses.begin(),
parameters.radiuses.end(),
search_radiuses.begin(),
[&](const boost::optional<double> &maybe_radius) {
double gps_radius = maybe_radius ? *maybe_radius : DEFAULT_GPS_PRECISION;
return search_radius_for_gps_radius(gps_radius);
[](const boost::optional<double> &maybe_radius) {
if (maybe_radius)
{
return *maybe_radius * RADIUS_MULTIPLIER;
}
else
{
return DEFAULT_GPS_PRECISION * RADIUS_MULTIPLIER;
}
});
}

View File

@ -370,7 +370,7 @@ Status TilePlugin::HandleRequest(const std::shared_ptr<datafacade::BaseDataFacad
// as the sort condition
std::sort(sorted_edge_indexes.begin(),
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
: edges[left].v < edges[right].v;
});

View File

@ -94,23 +94,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
@ -118,8 +116,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,25 +128,20 @@ util::Coordinate CoordinateExtractor::ExtractRepresentativeCoordinate(
// fallback, mostly necessary for dead ends
if (intersection_node == to_node)
{
const auto result = ExtractCoordinateAtLength(
skipping_inaccuracies_distance, coordinates);
BOOST_ASSERT(is_valid_result(result));
const auto result = ExtractCoordinateAtLength(skipping_inaccuracies_distance, coordinates);
// 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));
const auto result = ExtractCoordinateAtLength(skipping_inaccuracies_distance, coordinates);
// TODO: possibly re-enable with https://github.com/Project-OSRM/osrm-backend/issues/3470
// BOOST_ASSERT(not_same_as_start(result));
return result;
}
@ -168,22 +161,35 @@ util::Coordinate CoordinateExtractor::ExtractRepresentativeCoordinate(
if (coordinates.size() > 2 &&
util::coordinate_calculation::haversineDistance(turn_coordinate, coordinates[1]) <
ASSUMED_LANE_WIDTH)
{
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(is_valid_result(result));
BOOST_ASSERT(not_same_as_start(result));
return result;
}
else
{
BOOST_ASSERT(is_valid_result(coordinates.back()));
return 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();
}
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
@ -197,7 +203,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];
}
@ -237,7 +243,8 @@ util::Coordinate CoordinateExtractor::ExtractRepresentativeCoordinate(
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();
}
@ -252,14 +259,14 @@ util::Coordinate CoordinateExtractor::ExtractRepresentativeCoordinate(
// As a back-up, we have to check for this case
if (coordinates.front() == coordinates.back())
{
const auto result = ExtractCoordinateAtLength(
skipping_inaccuracies_distance, coordinates);
BOOST_ASSERT(is_valid_result(result));
const auto result =
ExtractCoordinateAtLength(skipping_inaccuracies_distance, coordinates);
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();
}
}
@ -299,7 +306,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;
}
@ -333,7 +340,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;
}
@ -354,7 +361,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;
}
@ -388,7 +395,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;
}
@ -414,18 +421,30 @@ 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;
}
}
}
// We use the locations on the regression line to offset the regression line onto the
// intersection.
const auto result =
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).
// 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
@ -989,7 +1008,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

View File

@ -2,8 +2,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>
@ -101,6 +103,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});
}
@ -120,8 +135,9 @@ IntersectionGenerator::ComputeIntersectionShape(const NodeID node_at_center_of_i
}
return util::reverseBearing(intersection.begin()->bearing);
}();
std::sort(
intersection.begin(), intersection.end(), makeCompareShapeDataByBearing(base_bearing));
std::sort(intersection.begin(),
intersection.end(),
makeCompareShapeDataAngleToBearing(base_bearing));
}
return intersection;
}

View File

@ -167,6 +167,14 @@ void IntersectionHandler::assignFork(const EdgeID via_edge,
node_based_graph.GetEdgeData(left.eid).road_classification.IsLowPriorityRoadClass();
const bool low_priority_right =
node_based_graph.GetEdgeData(right.eid).road_classification.IsLowPriorityRoadClass();
const auto same_mode_left =
in_data.travel_mode == node_based_graph.GetEdgeData(left.eid).travel_mode;
const auto same_mode_right =
in_data.travel_mode == node_based_graph.GetEdgeData(right.eid).travel_mode;
const auto suppressed_left_type =
same_mode_left ? TurnType::Suppressed : TurnType::Notification;
const auto suppressed_right_type =
same_mode_right ? TurnType::Suppressed : TurnType::Notification;
if ((angularDeviation(left.angle, STRAIGHT_ANGLE) < MAXIMAL_ALLOWED_NO_TURN_DEVIATION &&
angularDeviation(right.angle, STRAIGHT_ANGLE) > FUZZY_ANGLE_DIFFERENCE))
{
@ -198,7 +206,7 @@ void IntersectionHandler::assignFork(const EdgeID via_edge,
}
else
{
left.instruction = {TurnType::Suppressed, DirectionModifier::Straight};
left.instruction = {suppressed_left_type, DirectionModifier::Straight};
right.instruction = {findBasicTurnType(via_edge, right),
DirectionModifier::SlightRight};
}
@ -237,7 +245,7 @@ void IntersectionHandler::assignFork(const EdgeID via_edge,
}
else
{
right.instruction = {TurnType::Suppressed, DirectionModifier::Straight};
right.instruction = {suppressed_right_type, DirectionModifier::Straight};
left.instruction = {findBasicTurnType(via_edge, left),
DirectionModifier::SlightLeft};
}
@ -245,7 +253,7 @@ void IntersectionHandler::assignFork(const EdgeID via_edge,
}
// left side of fork
if (low_priority_right && !low_priority_left)
left.instruction = {TurnType::Suppressed, DirectionModifier::SlightLeft};
left.instruction = {suppressed_left_type, DirectionModifier::SlightLeft};
else
{
if (low_priority_left && !low_priority_right)
@ -256,7 +264,7 @@ void IntersectionHandler::assignFork(const EdgeID via_edge,
// right side of fork
if (low_priority_left && !low_priority_right)
right.instruction = {TurnType::Suppressed, DirectionModifier::SlightLeft};
right.instruction = {suppressed_right_type, DirectionModifier::SlightLeft};
else
{
if (low_priority_right && !low_priority_left)
@ -272,6 +280,12 @@ void IntersectionHandler::assignFork(const EdgeID via_edge,
ConnectedRoad &right) const
{
// TODO handle low priority road classes in a reasonable way
const auto suppressed_type = [&](const ConnectedRoad &road) {
const auto in_mode = node_based_graph.GetEdgeData(via_edge).travel_mode;
const auto out_mode = node_based_graph.GetEdgeData(road.eid).travel_mode;
return in_mode == out_mode ? TurnType::Suppressed : TurnType::Notification;
};
if (left.entry_allowed && center.entry_allowed && right.entry_allowed)
{
left.instruction = {TurnType::Fork, DirectionModifier::SlightLeft};
@ -285,7 +299,7 @@ void IntersectionHandler::assignFork(const EdgeID via_edge,
}
else
{
center.instruction = {TurnType::Suppressed, DirectionModifier::Straight};
center.instruction = {suppressed_type(center), DirectionModifier::Straight};
}
}
else

View File

@ -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;
}
}

View File

@ -301,12 +301,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
@ -544,14 +550,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);

View File

@ -566,6 +566,12 @@ std::pair<std::size_t, std::size_t> TurnHandler::findFork(const EdgeID via_edge,
return true;
}();
const auto has_compatible_modes = std::all_of(
intersection.begin() + right, intersection.begin() + left + 1, [&](const auto &road) {
return node_based_graph.GetEdgeData(road.eid).travel_mode ==
node_based_graph.GetEdgeData(via_edge).travel_mode;
});
// check if all entries in the fork range allow entry
const bool only_valid_entries = [&]() {
BOOST_ASSERT(right <= left && left < intersection.size());
@ -585,7 +591,8 @@ std::pair<std::size_t, std::size_t> TurnHandler::findFork(const EdgeID via_edge,
// TODO check whether 2*NARROW_TURN is too large
if (valid_indices && separated_at_left_side && separated_at_right_side &&
not_more_than_three && !has_obvious && has_compatible_classes && only_valid_entries)
not_more_than_three && !has_obvious && has_compatible_classes && only_valid_entries &&
has_compatible_modes)
return std::make_pair(right, left);
}
return std::make_pair(std::size_t{0}, std::size_t{0});

View File

@ -1,3 +1,4 @@
#include "storage/shared_barriers.hpp"
#include "storage/storage.hpp"
#include "util/exception.hpp"
#include "util/log.hpp"
@ -7,6 +8,9 @@
#include <boost/filesystem.hpp>
#include <boost/program_options.hpp>
#include <csignal>
#include <cstdlib>
using namespace osrm;
// generate boost::program_options object for the routing part
@ -87,8 +91,20 @@ bool generateDataStoreOptions(const int argc,
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 signals[] = {SIGTERM, SIGSEGV, SIGINT, SIGILL, SIGABRT, SIGFPE};
for (auto sig : signals)
{
std::signal(sig, CleanupSharedBarriers);
}
util::LogPolicy::GetInstance().Unmute();
boost::filesystem::path base_path;

View File

@ -152,6 +152,11 @@ double bearing(const Coordinate first_coordinate, const Coordinate second_coordi
{
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;
}

View File

@ -3,6 +3,7 @@
#include "engine/guidance/assemble_overview.hpp"
#include "engine/guidance/assemble_route.hpp"
#include "engine/guidance/assemble_steps.hpp"
#include "engine/guidance/post_processing.hpp"
#include <boost/test/test_case_template.hpp>
#include <boost/test/unit_test.hpp>
@ -17,4 +18,85 @@ BOOST_AUTO_TEST_CASE(rfc4648_test_vectors)
// TODO(daniel-j-h):
}
BOOST_AUTO_TEST_CASE(trim_short_segments)
{
using namespace osrm::extractor::guidance;
using namespace osrm::engine::guidance;
using namespace osrm::engine;
using namespace osrm::util;
Intersection intersection1{{FloatLongitude{-73.981154}, FloatLatitude{40.767762}},
{302},
{1},
Intersection::NO_INDEX,
0,
{0, 255},
{}};
Intersection intersection2{{FloatLongitude{-73.981495}, FloatLatitude{40.768275}},
{180},
{1},
0,
Intersection::NO_INDEX,
{0, 255},
{}};
// Check that duplicated coordinate in the end is removed
std::vector<RouteStep> steps = {{324,
"Central Park West",
"",
"",
"",
"",
"",
0.2,
1.9076601161280742,
TRAVEL_MODE_DRIVING,
{{FloatLongitude{-73.981492}, FloatLatitude{40.768258}},
329,
348,
{TurnType::ExitRotary, DirectionModifier::Straight},
WaypointType::Depart,
0},
0,
3,
{intersection1}},
{324,
"Central Park West",
"",
"",
"",
"",
"",
0,
0,
TRAVEL_MODE_DRIVING,
{{FloatLongitude{-73.981495}, FloatLatitude{40.768275}},
0,
0,
{TurnType::NoTurn, DirectionModifier::UTurn},
WaypointType::Arrive,
0},
2,
3,
{intersection2}}};
LegGeometry geometry;
geometry.locations = {{FloatLongitude{-73.981492}, FloatLatitude{40.768258}},
{FloatLongitude{-73.981495}, FloatLatitude{40.768275}},
{FloatLongitude{-73.981495}, FloatLatitude{40.768275}}};
geometry.segment_offsets = {0, 2};
geometry.segment_distances = {1.9076601161280742};
geometry.osm_node_ids = {OSMNodeID{0}, OSMNodeID{1}, OSMNodeID{2}};
geometry.annotations = {{1.9076601161280742, 0.2, 0}, {0, 0, 0}};
trimShortSegments(steps, geometry);
BOOST_CHECK_EQUAL(geometry.segment_distances.size(), 1);
BOOST_CHECK_EQUAL(geometry.segment_offsets.size(), 2);
BOOST_CHECK_EQUAL(geometry.segment_offsets.back(), 1);
BOOST_CHECK_EQUAL(geometry.annotations.size(), 1);
BOOST_CHECK_EQUAL(geometry.locations.size(), 2);
BOOST_CHECK_EQUAL(geometry.osm_node_ids.size(), 2);
}
BOOST_AUTO_TEST_SUITE_END()

View File

@ -32,7 +32,7 @@ BOOST_AUTO_TEST_CASE(test_tile)
const auto rc = osrm.Tile(params, result);
BOOST_CHECK(rc == Status::Ok);
BOOST_CHECK_EQUAL(result.size(), 114091);
BOOST_CHECK_EQUAL(result.size(), 114098);
protozero::pbf_reader tile_message(result);
tile_message.next();

View File

@ -117,8 +117,7 @@ BOOST_AUTO_TEST_CASE(compute_angle)
BOOST_CHECK_EQUAL(angle, 180);
// Tiny changes below our calculation resolution
// This should be equivalent to having two points on the same
// spot.
// This should be equivalent to having two points on the same spot.
first = Coordinate{FloatLongitude{0}, FloatLatitude{0}};
middle = Coordinate{FloatLongitude{1}, FloatLatitude{0}};
end = Coordinate{FloatLongitude{1 + std::numeric_limits<double>::epsilon()}, FloatLatitude{0}};
@ -126,14 +125,12 @@ BOOST_AUTO_TEST_CASE(compute_angle)
BOOST_CHECK_EQUAL(angle, 180);
// Invalid values
/* TODO: Enable this when I figure out how to use BOOST_CHECK_THROW
* and not have the whole test case fail...
first = Coordinate(FloatLongitude{0}, FloatLatitude{0});
middle = Coordinate(FloatLongitude{1}, FloatLatitude{0});
end = Coordinate(FloatLongitude(std::numeric_limits<double>::max()), FloatLatitude{0});
BOOST_CHECK_THROW( coordinate_calculation::computeAngle(first,middle,end),
BOOST_CHECK_THROW(
coordinate_calculation::computeAngle(
Coordinate(FloatLongitude{0}, FloatLatitude{0}),
Coordinate(FloatLongitude{1}, FloatLatitude{0}),
Coordinate(FloatLongitude{std::numeric_limits<double>::max()}, FloatLatitude{0})),
boost::numeric::positive_overflow);
*/
}
// Regression test for bug captured in #1347
@ -311,4 +308,15 @@ BOOST_AUTO_TEST_CASE(circleCenter)
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()

View File

@ -73,12 +73,14 @@ BOOST_AUTO_TEST_CASE(xyz_to_mercator)
double miny;
double maxx;
double maxy;
// http://tools.geofabrik.de/map/#13/85.0500/-175.5876&type=Geofabrik_Standard&grid=1
web_mercator::xyzToMercator(100, 0, 13, minx, miny, maxx, maxy);
BOOST_CHECK_CLOSE(minx, -19548311.361764118075, 0.0001);
BOOST_CHECK_CLOSE(miny, 19971868.8804085782, 0.0001);
BOOST_CHECK_CLOSE(miny, 20032616.372979045, 0.0001);
BOOST_CHECK_CLOSE(maxx, -19543419.391953866929, 0.0001);
BOOST_CHECK_CLOSE(maxy, 19971868.880408578, 0.0001);
BOOST_CHECK_CLOSE(maxy, 20037508.342789277, 0.0001); // Mercator 6378137*pi, WGS 85.0511
}
BOOST_AUTO_TEST_SUITE_END()