Compare commits
23 Commits
Author | SHA1 | Date | |
---|---|---|---|
|
54ab5373cf | ||
|
57bd2cda0f | ||
|
bfbdd18834 | ||
|
5159d57201 | ||
|
bc38275146 | ||
|
c77add50e2 | ||
|
37e36fd165 | ||
|
341109a8f4 | ||
|
a0b1a5df8c | ||
|
411313f666 | ||
|
ada0a1e8f8 | ||
|
74611f94fa | ||
|
eaff3b4210 | ||
|
1fb9f3e1eb | ||
|
6ea9f9fdf1 | ||
|
434a3a638a | ||
|
6305f4a529 | ||
|
646b1631ab | ||
|
a852ab1c43 | ||
|
ff25fc70f0 | ||
|
b34ed587d0 | ||
|
b58329104a | ||
|
d188e8e2a8 |
@ -13,6 +13,7 @@ notifications:
|
||||
branches:
|
||||
only:
|
||||
- master
|
||||
- 5.5
|
||||
|
||||
cache:
|
||||
ccache: true
|
||||
|
30
CHANGELOG.md
30
CHANGELOG.md
@ -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`
|
||||
|
||||
|
||||
|
@ -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}")
|
||||
|
@ -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, |
|
||||
|
@ -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 |
|
||||
|
@ -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 |
|
||||
|
@ -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
|
||||
{
|
||||
|
@ -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,
|
||||
|
@ -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) <
|
||||
|
@ -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)
|
||||
|
@ -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;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -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
|
||||
|
@ -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;
|
||||
|
@ -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
|
||||
|
@ -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;
|
||||
}
|
||||
|
||||
});
|
||||
}
|
||||
|
||||
|
@ -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;
|
||||
});
|
||||
|
@ -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;
|
||||
}
|
||||
|
||||
@ -169,21 +162,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
|
||||
@ -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));
|
||||
return 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
|
||||
|
@ -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;
|
||||
}
|
||||
|
@ -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
|
||||
|
@ -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;
|
||||
}
|
||||
}
|
||||
|
@ -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);
|
||||
|
@ -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});
|
||||
|
@ -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;
|
||||
|
@ -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;
|
||||
}
|
||||
|
||||
|
@ -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()
|
||||
|
@ -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();
|
||||
|
@ -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::numeric::positive_overflow);
|
||||
*/
|
||||
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()
|
||||
|
@ -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()
|
||||
|
Loading…
Reference in New Issue
Block a user