Compare commits

..

24 Commits

Author SHA1 Message Date
Daniel Patterson ca464fcd5d Tag for release. 2017-10-02 14:14:05 -07:00
Daniel Patterson e9b7b68427 Move workaround into single TU. 2017-10-02 14:06:49 -07:00
Daniel Patterson 6b8ae24df6 Needs some kind of std:: namespace import to find _throw_out_of_range symbol 2017-10-02 12:58:09 -07:00
Daniel Patterson 65385b55e9 Add include via cmake rather than environment variable - env variable breaks compiler detection. 2017-10-02 12:40:31 -07:00
Daniel Patterson f20dda55c0 Fix relative path to override include. 2017-10-02 12:22:43 -07:00
Daniel Patterson ff7f8557e3 Workaround GLIBC 4.9 importing one useless (to us) symbol that causes a version update. 2017-10-02 12:17:34 -07:00
Daniel Patterson eff1d4e622 Try 4.9 to see if that clears up a few of the C++14 errors. 2017-10-02 11:40:41 -07:00
Daniel Patterson f82908d509 Try downgrading libstdc++ so we can run inside non-upgrade glibc environments. 2017-10-02 11:18:33 -07:00
Frédéric Rodrigo b3b6e16940 Fix check_taginfo.py test for maxspeed tag in lower case 2017-09-30 22:16:51 +02:00
Frédéric Rodrigo f9fb0b84a8 Fix case of maxspeed tag values into taginfo.json 2017-09-30 22:16:51 +02:00
Frédéric Rodrigo 83acb46390 Add missing maxspeed tags into taginfo.json 2017-09-30 22:16:51 +02:00
Frédéric Rodrigo f36b3fb4bc Add to car profile missing BE:motorway maxspeed_table exceptions osm-fr/osmose-backend#232 2017-09-30 22:16:51 +02:00
Michael Krasnyk e7be271c43 Optimize MLD one-to-many getNodeQueryLevel 2017-09-29 13:38:52 +02:00
Michael Krasnyk 790b574114 unordered_multimap compilation fixes 2017-09-29 13:38:52 +02:00
Michael Krasnyk b3f59ab92c Move duplicated code into insert_node lambda 2017-09-29 13:38:52 +02:00
Michael Krasnyk f2333eb31a Break tie for equal weights but different durations
There is no possibility until multiple-weights are implemented
to break tie in the contraction and the direct shortest path plugin
as duration is not computed during contraction.

This must be fixed after multiple-weights implementation
by using `std::tie(weight, duration)` pairs everywhere.
2017-09-29 13:38:52 +02:00
Michael Krasnyk a862e5fb3a Implement one-to-many unidirectional MLD search 2017-09-29 13:38:52 +02:00
Michael Krasnyk 2715e5758b Split MLD many-to-many method 2017-09-29 13:38:52 +02:00
Michael Krasnyk 454487dd41 Refactor to reuse relaxOutgoingEdges in many-to-many plugin 2017-09-29 13:38:52 +02:00
Michael Krasnyk 2ed4f6eb0c Add suppression of libtbb memory leaks checking 2017-09-28 12:35:27 +02:00
Daniel J. Hofmann d7bcafcb59 Uses parsed len(turn:lanes) to fixup number of lanes, resolves #4472 2017-09-28 00:24:14 +02:00
Marcel Radischat c37a8ddd83 Update README.md with Docker+Node.js example 2017-09-26 09:16:59 +02:00
Michael Krasnyk fc3f96abcb Use pkg-config to find lua in non-standard locations 2017-09-26 09:03:57 +02:00
Michael Krasnyk c37ea441fc Bump osrm-deps package version 2017-09-25 12:26:47 +02:00
27 changed files with 635 additions and 429 deletions
+19 -14
View File
@@ -79,14 +79,14 @@ matrix:
apt:
sources: ['ubuntu-toolchain-r-test']
packages: ['g++-6', 'libbz2-dev', 'libxml2-dev', 'libzip-dev', 'liblua5.2-dev', 'libtbb-dev', 'libgdal-dev', 'libboost-all-dev']
env: CCOMPILER='gcc-6' CXXCOMPILER='g++-6' BUILD_TYPE='Debug' TARGET_ARCH='x86_64-asan' ENABLE_SANITIZER=ON CUCUMBER_TIMEOUT=20000
env: CCOMPILER='gcc-6' CXXCOMPILER='g++-6' BUILD_TYPE='Debug' TARGET_ARCH='x86_64-asan' ENABLE_SANITIZER=ON CUCUMBER_TIMEOUT=20000 LSAN_OPTIONS="suppressions=$TRAVIS_BUILD_DIR/scripts/travis/leaksanitizer.conf"
- os: linux
compiler: "clang-4.0-debug"
addons: &clang40
apt:
sources: ['ubuntu-toolchain-r-test']
packages: ['libstdc++-5-dev', 'libbz2-dev', 'libxml2-dev', 'libzip-dev', 'liblua5.2-dev', 'libtbb-dev', 'libgdal-dev', 'libboost-all-dev']
packages: ['libstdc++-4.9-dev', 'libbz2-dev', 'libxml2-dev', 'libzip-dev', 'liblua5.2-dev', 'libtbb-dev', 'libgdal-dev', 'libboost-all-dev']
env: CLANG_VERSION='4.0.0' BUILD_TYPE='Debug' CUCUMBER_TIMEOUT=60000
- os: linux
@@ -94,8 +94,8 @@ matrix:
addons:
apt:
sources: ['ubuntu-toolchain-r-test']
packages: ['libstdc++-5-dev']
env: CLANG_VERSION='4.0.0' BUILD_TYPE='Release' ENABLE_MASON=ON ENABLE_SANITIZER=ON
packages: ['libstdc++-4.9-dev']
env: CLANG_VERSION='4.0.0' BUILD_TYPE='Release' ENABLE_MASON=ON ENABLE_SANITIZER=ON LSAN_OPTIONS="suppressions=$TRAVIS_BUILD_DIR/scripts/travis/leaksanitizer.conf"
# Release Builds
- os: linux
@@ -103,7 +103,7 @@ matrix:
addons:
apt:
sources: ['ubuntu-toolchain-r-test']
packages: ['libstdc++-5-dev']
packages: ['libstdc++-4.9-dev']
env: CLANG_VERSION='4.0.0' BUILD_TYPE='Release' ENABLE_MASON=ON RUN_CLANG_FORMAT=ON ENABLE_LTO=ON
- os: linux
@@ -186,7 +186,7 @@ matrix:
addons:
apt:
sources: ['ubuntu-toolchain-r-test']
packages: ['libstdc++-5-dev']
packages: ['libstdc++-4.9-dev']
env: CLANG_VERSION='4.0.0' BUILD_TYPE='Release' ENABLE_MASON=ON ENABLE_LTO=ON JOBS=3
install:
- pushd ${OSRM_BUILD_DIR}
@@ -195,7 +195,8 @@ matrix:
-DENABLE_MASON=${ENABLE_MASON:-OFF} \
-DENABLE_NODE_BINDINGS=${ENABLE_NODE_BINDINGS:-OFF} \
-DENABLE_CCACHE=ON \
-DCMAKE_INSTALL_PREFIX=${OSRM_INSTALL_DIR}
-DCMAKE_INSTALL_PREFIX=${OSRM_INSTALL_DIR} \
-DENABLE_GLIBC_WORKAROUND=ON
- make --jobs=${JOBS}
- popd
script:
@@ -209,7 +210,7 @@ matrix:
addons:
apt:
sources: ['ubuntu-toolchain-r-test']
packages: ['libstdc++-5-dev']
packages: ['libstdc++-4.9-dev']
env: CLANG_VERSION='4.0.0' BUILD_TYPE='Debug' ENABLE_MASON=ON ENABLE_LTO=ON JOBS=3
install:
- pushd ${OSRM_BUILD_DIR}
@@ -218,7 +219,8 @@ matrix:
-DENABLE_MASON=${ENABLE_MASON:-OFF} \
-DENABLE_NODE_BINDINGS=${ENABLE_NODE_BINDINGS:-OFF} \
-DENABLE_CCACHE=ON \
-DCMAKE_INSTALL_PREFIX=${OSRM_INSTALL_DIR}
-DCMAKE_INSTALL_PREFIX=${OSRM_INSTALL_DIR} \
-DENABLE_GLIBC_WORKAROUND=ON
- make --jobs=${JOBS}
- popd
script:
@@ -232,7 +234,7 @@ matrix:
addons:
apt:
sources: ['ubuntu-toolchain-r-test']
packages: ['libstdc++-5-dev']
packages: ['libstdc++-4.9-dev']
env: CLANG_VERSION='4.0.0' BUILD_TYPE='Release' ENABLE_MASON=ON ENABLE_LTO=ON JOBS=3 NODE="6"
install:
- pushd ${OSRM_BUILD_DIR}
@@ -241,7 +243,8 @@ matrix:
-DENABLE_MASON=${ENABLE_MASON:-OFF} \
-DENABLE_NODE_BINDINGS=${ENABLE_NODE_BINDINGS:-OFF} \
-DENABLE_CCACHE=ON \
-DCMAKE_INSTALL_PREFIX=${OSRM_INSTALL_DIR}
-DCMAKE_INSTALL_PREFIX=${OSRM_INSTALL_DIR} \
-DENABLE_GLIBC_WORKAROUND=ON
- make --jobs=${JOBS}
- popd
script:
@@ -255,7 +258,7 @@ matrix:
addons:
apt:
sources: ['ubuntu-toolchain-r-test']
packages: ['libstdc++-5-dev']
packages: ['libstdc++-4.9-dev']
env: CLANG_VERSION='4.0.0' BUILD_TYPE='Debug' ENABLE_MASON=ON ENABLE_LTO=ON JOBS=3 NODE="6"
install:
- pushd ${OSRM_BUILD_DIR}
@@ -264,7 +267,8 @@ matrix:
-DENABLE_MASON=${ENABLE_MASON:-OFF} \
-DENABLE_NODE_BINDINGS=${ENABLE_NODE_BINDINGS:-OFF} \
-DENABLE_CCACHE=ON \
-DCMAKE_INSTALL_PREFIX=${OSRM_INSTALL_DIR}
-DCMAKE_INSTALL_PREFIX=${OSRM_INSTALL_DIR} \
-DENABLE_GLIBC_WORKAROUND=ON
- make --jobs=${JOBS}
- popd
script:
@@ -338,7 +342,8 @@ install:
-DENABLE_STXXL=${ENABLE_STXXL:-OFF} \
-DBUILD_TOOLS=ON \
-DENABLE_CCACHE=ON \
-DCMAKE_INSTALL_PREFIX=${OSRM_INSTALL_DIR}
-DCMAKE_INSTALL_PREFIX=${OSRM_INSTALL_DIR} \
-DENABLE_GLIBC_WORKAROUND=${ENABLE_GLIBC_WORKAROUND:-OFF}
- echo "travis_fold:start:MAKE"
- make --jobs=${JOBS}
- make tests --jobs=${JOBS}
+2 -1
View File
@@ -1,12 +1,13 @@
# UNRELEASED
- Profile:
- New function to support relations: `process_relation`. Read more in profiles documentation.
- Append cardinal directions from route relations to ref fields to improve instructions
- Support of `distance` weight in foot and bicycle profiles
- Infrastructure:
- Lua 5.1 support is removed due to lack of support in sol2 https://github.com/ThePhD/sol2/issues/302
- Node.js Bindings:
- Exposes `use_threads_number=Number` parameter of `EngineConfig` to limit a number of threads in a TBB internal pool
- Internals
- MLD uses a unidirectional Dijkstra for 1-to-N and N-to-1 matrices
# 5.12.0
- Guidance
+9 -6
View File
@@ -31,6 +31,7 @@ option(ENABLE_LTO "Use LTO if available" OFF)
option(ENABLE_FUZZING "Fuzz testing using LLVM's libFuzzer" OFF)
option(ENABLE_GOLD_LINKER "Use GNU gold linker if available" ON)
option(ENABLE_NODE_BINDINGS "Build NodeJs bindings" OFF)
option(ENABLE_GLIBC_WORKAROUND "Workaround GLIBC symbol exports" OFF)
list(APPEND CMAKE_MODULE_PATH "${CMAKE_CURRENT_SOURCE_DIR}/cmake")
@@ -517,12 +518,10 @@ else()
find_package(BZip2 REQUIRED)
add_dependency_includes(${BZIP2_INCLUDE_DIR})
FIND_PACKAGE(Lua 5.2 EXACT)
IF (LUA_FOUND)
MESSAGE(STATUS "Using Lua ${LUA_VERSION_STRING}")
ELSE()
MESSAGE(FATAL_ERROR "Lua 5.2 was not found.")
ENDIF()
find_package(Lua 5.2 REQUIRED)
if (LUA_FOUND)
message(STATUS "Using Lua ${LUA_VERSION_STRING}")
endif()
set(USED_LUA_LIBRARIES ${LUA_LIBRARIES})
add_dependency_includes(${LUA_INCLUDE_DIR})
@@ -812,6 +811,10 @@ add_custom_target(uninstall
add_subdirectory(unit_tests)
add_subdirectory(src/benchmarks)
if (ENABLE_GLIBC_WORKAROUND)
set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -DGLIBC_WORKAROUND")
endif()
if (ENABLE_NODE_BINDINGS)
add_subdirectory(src/nodejs)
endif()
+3 -1
View File
@@ -157,7 +157,9 @@ which will check and use pre-built binaries if they're available for this releas
to always force building the Node.js bindings from source.
For usage details have a look [these API docs](docs/nodejs/api.md).
For usage details have a look [these API docs](docs/nodejs/api.md).
An exemplary implementation by a 3rd party with Docker and Node.js can be found [here](https://github.com/door2door-io/osrm-express-server-demo).
## References in publications
+1 -1
View File
@@ -40,7 +40,7 @@ ECHO msbuild version
msbuild /version
:: HARDCODE "x64" as it is uppercase on AppVeyor and download from S3 is case sensitive
SET DEPSPKG=osrm-deps-win-x64-14.0.7z
SET DEPSPKG=osrm-deps-win-x64-14.0-2017.09.7z
:: local development
ECHO.
+3
View File
@@ -36,6 +36,8 @@
# This is because, the lua location is not standardized and may exist in
# locations other than lua/
include(FindPkgConfig)
unset(_lua_include_subdirs)
unset(_lua_library_names)
unset(_lua_append_versions)
@@ -81,6 +83,7 @@ function(_lua_set_version_vars)
lua-${CMAKE_MATCH_1}.${CMAKE_MATCH_2}
lua.${CMAKE_MATCH_1}.${CMAKE_MATCH_2}
)
pkg_check_modules(LUA QUIET "lua${ver}")
endforeach ()
set(_lua_include_subdirs "${_lua_include_subdirs}" PARENT_SCOPE)
+3 -3
View File
@@ -7,7 +7,7 @@ RUN NPROC=$(grep -c ^processor /proc/cpuinfo 2>/dev/null || 1) && \
echo "@testing http://dl-cdn.alpinelinux.org/alpine/edge/testing" >> /etc/apk/repositories && \
apk update && \
apk upgrade && \
apk add git cmake wget make libc-dev gcc g++ bzip2-dev boost-dev zlib-dev expat-dev lua5.1-dev libtbb@testing libtbb-dev@testing && \
apk add git cmake wget make libc-dev gcc g++ bzip2-dev boost-dev zlib-dev expat-dev lua5.2-dev libtbb@testing libtbb-dev@testing && \
\
echo "Building libstxxl" && \
cd /opt && \
@@ -46,8 +46,8 @@ RUN NPROC=$(grep -c ^processor /proc/cpuinfo 2>/dev/null || 1) && \
rm /usr/local/lib/libstxxl* && \
cd /opt && \
apk del boost-dev && \
apk del g++ cmake libc-dev expat-dev zlib-dev bzip2-dev lua5.1-dev git make gcc && \
apk add boost-filesystem boost-program_options boost-regex boost-iostreams boost-thread libgomp lua5.1 expat && \
apk del g++ cmake libc-dev expat-dev zlib-dev bzip2-dev lua5.2-dev git make gcc && \
apk add boost-filesystem boost-program_options boost-regex boost-iostreams boost-thread libgomp lua5.2 expat && \
rm -rf /src /opt/stxxl /usr/local/bin/stxxl_tool /usr/local/lib/libosrm*
EXPOSE 5000
-68
View File
@@ -1,68 +0,0 @@
@routing @car @relations
Feature: Car - route relations
Background:
Given the profile "car"
@sliproads
Scenario: Cardinal direction assignment to refs
Given the node map
"""
a b
| |
c------+--+------d
e------+--+------f
| |
g h
i----------------j
k----------------l
x----------------y
z----------------w
"""
And the ways
| nodes | name | highway | ref |
| ag | southbound | motorway | I 80 |
| hb | northbound | motorway | I 80 |
| dc | westbound | motorway | I 85;CO 93 |
| ef | eastbound | motorway | I 85;US 12 |
| ij | westbound-2 | motorway | I 99 |
| ji | eastbound-2 | motorway | I 99 |
| kl | eastbound-2 | motorway | I 99 |
| lk | eastbound-2 | motorway | I 99 |
| xy | watermill | motorway | I 45M; US 3 |
And the relations
| type | way:south | route | ref |
| route | ag | road | 80 |
| route | ef | road | 12 |
And the relations
| type | way:north | route | ref |
| route | hb | road | 80 |
| route | cd | road | 93 |
And the relations
| type | way:west | route | ref |
| route | dc | road | 85 |
| route | ij | road | 99 |
| route | xy | road | I 45 |
And the relations
| type | way:east | route | ref |
| route | lk | road | I 99 |
And the relations
| type | way:east | route | ref |
| route | xy | road | US 3 |
When I route I should get
| waypoints | route | ref |
| a,g | southbound,southbound | I 80 $south,I 80 $south |
| h,b | northbound,northbound | I 80 $north,I 80 $north |
| d,c | westbound,westbound | I 85 $west; CO 93 $north,I 85 $west; CO 93 $north |
| e,f | eastbound,eastbound | I 85; US 12 $south,I 85; US 12 $south |
| i,j | westbound-2,westbound-2 | I 99 $west,I 99 $west |
| l,k | eastbound-2,eastbound-2 | I 99 $east,I 99 $east |
| x,y | watermill,watermill | I 45M $west; US 3 $east,I 45M $west; US 3 $east |
+29
View File
@@ -280,6 +280,35 @@ Feature: Simple Turns
| a,d | road,road | depart,arrive |
| e,a | road,road | depart,arrive |
Scenario: Splitting Road with many lanes; same as above makes sure len(turn:lanes) work as expected
Given the node map
"""
f - - - - - - - - - - - - - - - - - - - - e
'
'
'
'
'
a - - - - - b
'
'
'
'
'
c - - - - - - - - - - - - - - - - - - - - d
"""
And the ways
| nodes | highway | name | turn:lanes | oneway |
| ab | primary | road | left\|left\|right\|right | no |
| bcd | primary | road | through\|through | yes |
| efb | primary | road | through\|through | yes |
When I route I should get
| waypoints | route | turns |
| a,d | road,road | depart,arrive |
| e,a | road,road | depart,arrive |
@todo
# currently the intersections don't match up do to the `merging` process.
# The intermediate intersection is technically no-turn at all, since the road continues.
+1 -1
View File
@@ -11,7 +11,7 @@ module.exports = function () {
var waypoints = [],
columnHeaders = tableRows[0].slice(1),
rowHeaders = tableRows.map((h) => h[0]).slice(1),
symmetric = columnHeaders.every((ele, i) => ele === rowHeaders[i]);
symmetric = columnHeaders.length == rowHeaders.length && columnHeaders.every((ele, i) => ele === rowHeaders[i]);
if (symmetric) {
columnHeaders.forEach((nodeName) => {
+67
View File
@@ -41,6 +41,17 @@ Feature: Basic Distance Matrix
| c | 30 | 20 | 0 | 30 |
| d | 60 | 50 | 30 | 0 |
When I request a travel time matrix I should get
| | a | b | c | d |
| a | 0 | 10 | 30 | 60 |
When I request a travel time matrix I should get
| | a |
| a | 0 |
| b | 10 |
| c | 30 |
| d | 60 |
Scenario: Testbot - Travel time matrix with fuzzy match
Given the node map
"""
@@ -132,6 +143,13 @@ Feature: Basic Distance Matrix
| | a | b | e | f |
| a | 0 | 10 | 20 | 30 |
When I request a travel time matrix I should get
| | a |
| a | 0 |
| b | 10 |
| e | 20 |
| f | 30 |
Scenario: Testbot - Travel time 3x2 matrix
Given the node map
"""
@@ -308,3 +326,52 @@ Feature: Basic Distance Matrix
| 6 | 7 | 6 | 10 | 9 | 1 | 0 | 3.9 | 2.9 |
| 7 | 3.1 | 2.1 | 6.1 | 5.1 | 9.1 | 8.1 | 0 | 11 |
| 8 | 4.1 | 3.1 | 7.1 | 6.1 | 10.1 | 9.1 | 1 | 0 |
Scenario: Testbot - Travel time matrix with ties
Given the profile file
"""
local functions = require('testbot')
functions.process_segment = function(profile, segment)
segment.weight = 1
segment.duration = 1
end
functions.process_turn = function(profile, turn)
if turn.angle >= 0 then
turn.duration = 16
else
turn.duration = 4
end
turn.weight = 0
end
return functions
"""
And the node map
"""
a b
c d
"""
And the ways
| nodes |
| ab |
| ac |
| bd |
| dc |
When I route I should get
| from | to | route | distance | time | weight |
| a | c | ac,ac | 200m | 5s | 5 |
When I request a travel time matrix I should get
| | a | b | c | d |
| a | 0 | 1 | 5 | 10 |
When I request a travel time matrix I should get
| | a |
| a | 0 |
| b | 1 |
| c | 15 |
| d | 10 |
+9 -5
View File
@@ -159,14 +159,16 @@ class CellCustomizer
}
const EdgeWeight to_weight = weight + subcell_weight;
const EdgeDuration to_duration = duration + *subcell_duration;
if (!heap.WasInserted(to))
{
heap.Insert(to, to_weight, {true, duration + *subcell_duration});
heap.Insert(to, to_weight, {true, to_duration});
}
else if (to_weight < heap.GetKey(to))
else if (std::tie(to_weight, to_duration) <
std::tie(heap.GetKey(to), heap.GetData(to).duration))
{
heap.DecreaseKey(to, to_weight);
heap.GetData(to) = {true, duration + *subcell_duration};
heap.GetData(to) = {true, to_duration};
}
}
@@ -191,14 +193,16 @@ class CellCustomizer
partition.GetCell(level - 1, node) != partition.GetCell(level - 1, to)))
{
const EdgeWeight to_weight = weight + data.weight;
const EdgeDuration to_duration = duration + data.duration;
if (!heap.WasInserted(to))
{
heap.Insert(to, to_weight, {false, duration + data.duration});
}
else if (to_weight < heap.GetKey(to))
else if (std::tie(to_weight, to_duration) <
std::tie(heap.GetKey(to), heap.GetData(to).duration))
{
heap.DecreaseKey(to, to_weight);
heap.GetData(to) = {false, duration + data.duration};
heap.GetData(to) = {false, to_duration};
}
}
}
+3 -13
View File
@@ -30,7 +30,7 @@ class RoutingAlgorithmsInterface
virtual InternalRouteResult
DirectShortestPathSearch(const PhantomNodes &phantom_node_pair) const = 0;
virtual std::vector<EdgeWeight>
virtual std::vector<EdgeDuration>
ManyToManySearch(const std::vector<PhantomNode> &phantom_nodes,
const std::vector<std::size_t> &source_indices,
const std::vector<std::size_t> &target_indices) const = 0;
@@ -81,7 +81,7 @@ template <typename Algorithm> class RoutingAlgorithms final : public RoutingAlgo
InternalRouteResult
DirectShortestPathSearch(const PhantomNodes &phantom_nodes) const final override;
std::vector<EdgeWeight>
std::vector<EdgeDuration>
ManyToManySearch(const std::vector<PhantomNode> &phantom_nodes,
const std::vector<std::size_t> &source_indices,
const std::vector<std::size_t> &target_indices) const final override;
@@ -166,16 +166,6 @@ RoutingAlgorithms<Algorithm>::DirectShortestPathSearch(const PhantomNodes &phant
return routing_algorithms::directShortestPathSearch(heaps, *facade, phantom_nodes);
}
template <typename Algorithm>
std::vector<EdgeWeight>
RoutingAlgorithms<Algorithm>::ManyToManySearch(const std::vector<PhantomNode> &phantom_nodes,
const std::vector<std::size_t> &source_indices,
const std::vector<std::size_t> &target_indices) const
{
return routing_algorithms::manyToManySearch(
heaps, *facade, phantom_nodes, source_indices, target_indices);
}
template <typename Algorithm>
inline routing_algorithms::SubMatchingList RoutingAlgorithms<Algorithm>::MapMatching(
const routing_algorithms::CandidateLists &candidates_list,
@@ -211,7 +201,7 @@ InternalManyRoutesResult inline RoutingAlgorithms<
}
template <>
inline std::vector<EdgeWeight>
inline std::vector<EdgeDuration>
RoutingAlgorithms<routing_algorithms::corech::Algorithm>::ManyToManySearch(
const std::vector<PhantomNode> &,
const std::vector<std::size_t> &,
@@ -17,11 +17,23 @@ namespace routing_algorithms
{
template <typename Algorithm>
std::vector<EdgeWeight> manyToManySearch(SearchEngineData<Algorithm> &engine_working_data,
const DataFacade<Algorithm> &facade,
const std::vector<PhantomNode> &phantom_nodes,
std::vector<std::size_t> source_indices,
std::vector<std::size_t> target_indices);
std::vector<EdgeDuration> manyToManySearch(SearchEngineData<Algorithm> &engine_working_data,
const DataFacade<Algorithm> &facade,
const std::vector<PhantomNode> &phantom_nodes,
std::vector<std::size_t> source_indices,
std::vector<std::size_t> target_indices);
namespace mld
{
template <bool DIRECTION>
std::vector<EdgeDuration> oneToManySearch(SearchEngineData<Algorithm> &engine_working_data,
const DataFacade<Algorithm> &facade,
const std::vector<PhantomNode> &phantom_nodes,
std::size_t phantom_index,
std::vector<std::size_t> phantom_indices);
} // mld
} // namespace routing_algorithms
} // namespace engine
@@ -132,44 +132,16 @@ retrievePackedPathFromHeap(const SearchEngineData<Algorithm>::QueryHeap &forward
}
template <bool DIRECTION, typename Algorithm, typename... Args>
void routingStep(const DataFacade<Algorithm> &facade,
typename SearchEngineData<Algorithm>::QueryHeap &forward_heap,
typename SearchEngineData<Algorithm>::QueryHeap &reverse_heap,
NodeID &middle_node,
EdgeWeight &path_upper_bound,
const bool force_loop_forward,
const bool force_loop_reverse,
Args... args)
void relaxOutgoingEdges(const DataFacade<Algorithm> &facade,
typename SearchEngineData<Algorithm>::QueryHeap &forward_heap,
const NodeID node,
const EdgeWeight weight,
Args... args)
{
const auto &partition = facade.GetMultiLevelPartition();
const auto &cells = facade.GetCellStorage();
const auto &metric = facade.GetCellMetric();
const auto node = forward_heap.DeleteMin();
const auto weight = forward_heap.GetKey(node);
BOOST_ASSERT(!facade.ExcludeNode(node));
// Upper bound for the path source -> target with
// weight(source -> node) = weight weight(to -> target) ≤ reverse_weight
// is weight + reverse_weight
// More tighter upper bound requires additional condition reverse_heap.WasRemoved(to)
// with weight(to -> target) = reverse_weight and all weights ≥ 0
if (reverse_heap.WasInserted(node))
{
auto reverse_weight = reverse_heap.GetKey(node);
auto path_weight = weight + reverse_weight;
// if loops are forced, they are so at the source
if (!(force_loop_forward && forward_heap.GetData(node).parent == node) &&
!(force_loop_reverse && reverse_heap.GetData(node).parent == node) &&
(path_weight >= 0) && (path_weight < path_upper_bound))
{
middle_node = node;
path_upper_bound = path_weight;
}
}
const auto level = getNodeQueryLevel(partition, node, args...);
if (level >= 1 && !forward_heap.GetData(node).from_clique_arc)
@@ -258,6 +230,45 @@ void routingStep(const DataFacade<Algorithm> &facade,
}
}
template <bool DIRECTION, typename Algorithm, typename... Args>
void routingStep(const DataFacade<Algorithm> &facade,
typename SearchEngineData<Algorithm>::QueryHeap &forward_heap,
typename SearchEngineData<Algorithm>::QueryHeap &reverse_heap,
NodeID &middle_node,
EdgeWeight &path_upper_bound,
const bool force_loop_forward,
const bool force_loop_reverse,
Args... args)
{
const auto node = forward_heap.DeleteMin();
const auto weight = forward_heap.GetKey(node);
BOOST_ASSERT(!facade.ExcludeNode(node));
// Upper bound for the path source -> target with
// weight(source -> node) = weight weight(to -> target) ≤ reverse_weight
// is weight + reverse_weight
// More tighter upper bound requires additional condition reverse_heap.WasRemoved(to)
// with weight(to -> target) = reverse_weight and all weights ≥ 0
if (reverse_heap.WasInserted(node))
{
auto reverse_weight = reverse_heap.GetKey(node);
auto path_weight = weight + reverse_weight;
// if loops are forced, they are so at the source
if (!(force_loop_forward && forward_heap.GetData(node).parent == node) &&
!(force_loop_reverse && reverse_heap.GetData(node).parent == node) &&
(path_weight >= 0) && (path_weight < path_upper_bound))
{
middle_node = node;
path_upper_bound = path_weight;
}
}
// Relax outgoing edges from node
relaxOutgoingEdges<DIRECTION>(facade, forward_heap, node, weight, args...);
}
// With (s, middle, t) we trace back the paths middle -> s and middle -> t.
// This gives us a packed path (node ids) from the base graph around s and t,
// and overlay node ids otherwise. We then have to unpack the overlay clique
+1 -1
View File
@@ -1,6 +1,6 @@
{
"name": "osrm",
"version": "5.13.0-cardinal.1",
"version": "5.13.0-glibc.1",
"private": false,
"description": "The Open Source Routing Machine is a high performance routing engine written in C++14 designed to run on OpenStreetMap data.",
"dependencies": {
+4 -74
View File
@@ -1,14 +1,12 @@
-- Car profile
api_version = 3
api_version = 2
Set = require('lib/set')
Sequence = require('lib/sequence')
Handlers = require("lib/way_handlers")
Relations = require("lib/relations")
find_access_tag = require("lib/access").find_access_tag
limit = require("lib/maxspeed").limit
Utils = require("lib/utils")
function setup()
local use_left_hand_driving = false
@@ -252,6 +250,7 @@ function setup()
-- List only exceptions
maxspeed_table = {
["be:motorway"] = 120,
["ch:rural"] = 80,
["ch:trunk"] = 100,
["ch:motorway"] = 120,
@@ -281,7 +280,7 @@ function setup()
}
end
function process_node(profile, node, result, relations)
function process_node(profile, node, result)
-- parse access and barrier tags
local access = find_access_tag(node, profile.access_tags_hierarchy)
if access then
@@ -308,7 +307,7 @@ function process_node(profile, node, result, relations)
end
end
function process_way(profile, way, result, relations)
function process_way(profile, way, result)
-- the intial filtering of ways based on presence of tags
-- affects processing times significantly, because all ways
-- have to be checked.
@@ -392,74 +391,6 @@ function process_way(profile, way, result, relations)
}
WayHandlers.run(profile,way,result,data,handlers)
-- now process relations data
local matched_refs = nil;
if result.ref then
local match_res = Relations.match_to_ref(relations, result.ref)
local ref = ''
for _, m in pairs(match_res) do
if ref ~= '' then
ref = ref .. '; '
end
if m.dir then
ref = ref .. m.ref .. ' $' .. m.dir
else
ref = ref .. m.ref
end
end
result.ref = ref
end
end
function process_relation(profile, relation, result)
local t = relation:get_value_by_key("type")
function add_extra_data(m)
local name = relation:get_value_by_key("name")
if name then
result[m]['route_name'] = name
end
local ref = relation:get_value_by_key("ref")
if ref then
result[m]['route_ref'] = ref
end
end
if t == 'route' then
local route = relation:get_value_by_key("route")
if route == 'road' then
for _, m in ipairs(relation:members()) do
-- process case, where directions set as role
local role = string.lower(m:role())
if role == 'north' or role == 'south' or role == 'west' or role == 'east' then
result[m]['route_direction'] = role
add_extra_data(m)
end
end
end
local direction = relation:get_value_by_key('direction')
if direction then
direction = string.lower(direction)
if direction == 'north' or direction == 'south' or direction == 'west' or direction == 'east' then
for _, m in ipairs(relation:members()) do
if m:role() == 'forward' then
result[m]['route_direction'] = direction
add_extra_data(m)
end
end
end
end
end
end
function process_turn(profile, turn)
@@ -504,6 +435,5 @@ return {
setup = setup,
process_way = process_way,
process_node = process_node,
process_relation = process_relation,
process_turn = process_turn
}
-94
View File
@@ -1,94 +0,0 @@
-- Profile functions dealing with various aspects of relation parsing
--
-- You can run a selection you find useful in your profile,
-- or do you own processing if/when required.
Utils = require('lib/utils')
Relations = {}
-- match ref values to relations data
function Relations.match_to_ref(relations, ref)
function calculate_scores(refs, tag_value)
local tag_tokens = Set(Utils.tokenize_common(tag_value))
local result = {}
for i, r in ipairs(refs) do
local ref_tokens = Utils.tokenize_common(r)
local score = 0
for _, t in ipairs(ref_tokens) do
if tag_tokens[t] then
if Utils.is_number(t) then
score = score + 2
else
score = score + 1
end
end
end
result[r] = score
end
return result
end
local references = Utils.string_list_tokens(ref)
local result_match = {}
local order = {}
for i, r in ipairs(references) do
result_match[r] = false
order[i] = r
end
for i, rel in ipairs(relations) do
local name_scores = nil
local name_tokens = {}
local route_name = rel["route_name"]
if route_name then
name_scores = calculate_scores(references, route_name)
end
local ref_scores = nil
local ref_tokens = {}
local route_ref = rel["route_ref"]
if route_ref then
ref_scores = calculate_scores(references, route_ref)
end
-- merge scores
local direction = rel["route_direction"]
if direction then
local best_score = -1
local best_ref = nil
function find_best(scores)
if scores then
for k ,v in pairs(scores) do
if v > best_score then
best_ref = k
best_score = v
end
end
end
end
find_best(name_scores)
find_best(ref_scores)
if best_ref then
result_match[best_ref] = direction
end
end
end
local result = {}
for i, r in ipairs(order) do
result[i] = { ref = r, dir = result_match[r] };
end
return result
end
return Relations
-43
View File
@@ -1,43 +0,0 @@
-- Profile functions to implement common algorithms of data processing
--
-- You can run a selection you find useful in your profile,
-- or do you own processing if/when required.
Utils = {}
-- split string 'a; b; c' to table with values ['a', 'b', 'c']
-- so it use just one separator ';'
function Utils.string_list_tokens(str)
result = {}
local idx = 0
for s in str.gmatch(str, "([^;]*)") do
if s ~= nil and s ~= '' then
idx = idx + 1
result[idx] = s:gsub("^%s*(.-)%s*$", "%1")
end
end
return result
end
-- same as Utils.StringListTokens, but with many possible separators:
-- ',' | ';' | ' '| '(' | ')'
function Utils.tokenize_common(str)
result = {}
local idx = 0
for s in str.gmatch(str, "%S+") do
if s ~= nil and s ~= '' then
idx = idx + 1
result[idx] = s:gsub("^%s*(.-)%s*$", "%1")
end
end
return result
end
-- returns true, if string contains a number
function Utils.is_number(str)
return (tonumber(str) ~= nil)
end
return Utils
+2
View File
@@ -19,6 +19,8 @@ with open(taginfo_path) as f:
valid_strings = [t["key"] for t in taginfo["tags"]]
valid_strings += [t["value"] for t in taginfo["tags"] if "value" in t]
valid_strings += [t["value"].lower() for t in taginfo["tags"] if "value" in t] # lower is for max speed
valid_strings = set(valid_strings)
string_regxp = re.compile("\"([\d\w\_:]+)\"")
+21 -9
View File
@@ -145,7 +145,8 @@ class SVGPrinter (gdb.Command):
self.to_svg = {
'const osrm::engine::datafacade::ContiguousInternalMemoryDataFacade<osrm::engine::routing_algorithms::ch::Algorithm> &': self.Facade,
'const osrm::engine::datafacade::ContiguousInternalMemoryDataFacade<osrm::engine::routing_algorithms::corech::Algorithm> &': self.Facade,
'const osrm::engine::datafacade::ContiguousInternalMemoryDataFacade<osrm::engine::routing_algorithms::mld::Algorithm> &': self.Facade}
'const osrm::engine::datafacade::ContiguousInternalMemoryDataFacade<osrm::engine::routing_algorithms::mld::Algorithm> &': self.Facade,
'osrm::engine::DataFacade': self.Facade}
@staticmethod
@@ -258,17 +259,27 @@ class SVGPrinter (gdb.Command):
geometry_first = geometry['_M_impl']['_M_start']
for segment, weight in enumerate(iterate(weights)):
ref = 's' + str(node) + '.' + str(segment)
result += '<path id="' + ref + '" class="segment" d="' \
+ 'M' + t(lonlat(call(facade, 'GetCoordinateOfNode', geometry_first.dereference()))) + ' ' \
+ 'L' + t(lonlat(call(facade, 'GetCoordinateOfNode', (geometry_first+1).dereference()))) + '" />'\
+ '<text class="segment weight ' + direction + '">'\
+ '<textPath xlink:href="#' + ref + '" startOffset="50%">' \
+ segment_weight(weight) + '</textPath></text>\n'
fr = lonlat(call(facade, 'GetCoordinateOfNode', geometry_first.dereference()))
to = lonlat(call(facade, 'GetCoordinateOfNode', (geometry_first+1).dereference()))
if fr == to:
## node penalty on zero length segment (traffic light)
result += '<text class="segment weight ' + direction \
+ '" x="' + str(tx(fr[0])) + '" y="' + str(ty(fr[1])) \
+ '" font="Arial" font-size="32" rotate="0" text-anchor="middle" >' \
+ '&#x1F6A6; ' + segment_weight(weight) + '</text>\n'
else:
## normal segment
result += '<path id="' + ref + '" class="segment" d="' \
+ 'M' + t(fr) + ' ' \
+ 'L' + t(to) + '" />'\
+ '<text class="segment weight ' + direction + '">'\
+ '<textPath xlink:href="#' + ref + '" startOffset="50%">' \
+ segment_weight(weight) + '</textPath></text>\n'
geometry_first += 1
## add edge-based edges
s0, s1 = geometry['_M_impl']['_M_start'].dereference(), (geometry['_M_impl']['_M_start'] + 1).dereference()
for edge in range(call(facade, 'BeginEdges', node), call(facade, 'EndEdges', node)):
for edge in []: # range(call(facade, 'BeginEdges', node), call(facade, 'EndEdges', node)): adjust to GetAdjacentEdgeRange
target, edge_data = call(facade, 'GetTarget', edge), call(facade, 'GetEdgeData', edge)
direction = 'both' if edge_data['forward'] and edge_data['backward'] else 'forward' if edge_data['forward'] else 'backward'
target_geometry = SVGPrinter.getByGeometryId(facade, call(facade, 'GetGeometryIndex', target), 'Geometry')
@@ -323,7 +334,8 @@ class SVGPrinter (gdb.Command):
re_float = '[-+]?[0-9]*\.?[0-9]+'
bbox = re.search('(' + re_float + '),(' + re_float + ');(' + re_float + '),(' + re_float +')', arg)
bbox = [float(x) for x in bbox.groups()] if bbox else [-180, -90, 180, 90]
svg = self.to_svg[str(val.type)](val, width, height, bbox)
type = val.type.target().unqualified() if val.type.code == gdb.TYPE_CODE_REF else val.type
svg = self.to_svg[str(type)](val, width, height, bbox)
self.show_svg(svg, width, height)
except KeyError as e:
print ('no SVG printer for: ' + str(e))
+8
View File
@@ -0,0 +1,8 @@
# Configuration file for LeakSanitizer run on the Travis CI
# TBB leaks some memory allocated in singleton depending on deinitialization order
# Direct leak of 1560 byte(s) in 3 object(s) allocated from:
# #0 0x7f7ae72a80a0 in operator new[](unsigned long) (/usr/lib/x86_64-linux-gnu/libasan.so.3+0xc80a0)
# #1 0x7f7ae595d13e (/usr/lib/x86_64-linux-gnu/libtbb.so.2+0x2213e)
leak:libtbb.so
+56
View File
@@ -0,0 +1,56 @@
#include "engine/routing_algorithms.hpp"
namespace osrm
{
namespace engine
{
template <typename Algorithm>
std::vector<EdgeDuration>
RoutingAlgorithms<Algorithm>::ManyToManySearch(const std::vector<PhantomNode> &phantom_nodes,
const std::vector<std::size_t> &source_indices,
const std::vector<std::size_t> &target_indices) const
{
return routing_algorithms::manyToManySearch(
heaps, *facade, phantom_nodes, source_indices, target_indices);
}
template std::vector<EdgeDuration>
RoutingAlgorithms<routing_algorithms::ch::Algorithm>::ManyToManySearch(
const std::vector<PhantomNode> &phantom_nodes,
const std::vector<std::size_t> &source_indices,
const std::vector<std::size_t> &target_indices) const;
template std::vector<EdgeDuration>
RoutingAlgorithms<routing_algorithms::corech::Algorithm>::ManyToManySearch(
const std::vector<PhantomNode> &phantom_nodes,
const std::vector<std::size_t> &source_indices,
const std::vector<std::size_t> &target_indices) const;
// One-to-many and many-to-one can be handled with MLD separately from many-to-many search.
// One-to-many (many-to-one) search is a unidirectional forward (backward) Dijkstra search
// with the candidate node level min(GetQueryLevel(phantom_node, phantom_nodes, node)
template <>
std::vector<EdgeDuration> RoutingAlgorithms<routing_algorithms::mld::Algorithm>::ManyToManySearch(
const std::vector<PhantomNode> &phantom_nodes,
const std::vector<std::size_t> &source_indices,
const std::vector<std::size_t> &target_indices) const
{
if (source_indices.size() == 1)
{ // TODO: check if target_indices.size() == 1 and do a bi-directional search
return routing_algorithms::mld::oneToManySearch<routing_algorithms::FORWARD_DIRECTION>(
heaps, *facade, phantom_nodes, source_indices.front(), target_indices);
}
if (target_indices.size() == 1)
{
return routing_algorithms::mld::oneToManySearch<routing_algorithms::REVERSE_DIRECTION>(
heaps, *facade, phantom_nodes, target_indices.front(), source_indices);
}
return routing_algorithms::manyToManySearch(
heaps, *facade, phantom_nodes, source_indices, target_indices);
}
} // namespace engine
} // namespace osrm
+251 -21
View File
@@ -104,7 +104,8 @@ void relaxOutgoingEdges(const DataFacade<ch::Algorithm> &facade,
query_heap.Insert(to, to_weight, {node, to_duration});
}
// Found a shorter Path -> Update weight
else if (to_weight < query_heap.GetKey(to))
else if (std::tie(to_weight, to_duration) <
std::tie(query_heap.GetKey(to), query_heap.GetData(to).duration))
{
// new parent
query_heap.GetData(to) = {node, to_duration};
@@ -120,13 +121,60 @@ addLoopWeight(const DataFacade<mld::Algorithm> &, const NodeID, EdgeWeight &, Ed
return false;
}
template <bool DIRECTION>
template <typename MultiLevelPartition>
inline LevelID getNodeQueryLevel(const MultiLevelPartition &partition,
NodeID node,
const PhantomNode &phantom_node)
{
auto highest_diffrent_level = [&partition, node](const SegmentID &phantom_node) {
if (phantom_node.enabled)
return partition.GetHighestDifferentLevel(phantom_node.id, node);
return INVALID_LEVEL_ID;
};
return std::min(highest_diffrent_level(phantom_node.forward_segment_id),
highest_diffrent_level(phantom_node.reverse_segment_id));
}
template <typename MultiLevelPartition>
inline LevelID getNodeQueryLevel(const MultiLevelPartition &partition,
NodeID node,
const std::vector<PhantomNode> &phantom_nodes,
const std::size_t phantom_index,
const std::vector<std::size_t> &phantom_indices)
{
auto min_level = [&partition, node](const PhantomNode &phantom_node) {
const auto &forward_segment = phantom_node.forward_segment_id;
const auto forward_level =
forward_segment.enabled ? partition.GetHighestDifferentLevel(node, forward_segment.id)
: INVALID_LEVEL_ID;
const auto &reverse_segment = phantom_node.reverse_segment_id;
const auto reverse_level =
reverse_segment.enabled ? partition.GetHighestDifferentLevel(node, reverse_segment.id)
: INVALID_LEVEL_ID;
return std::min(forward_level, reverse_level);
};
// Get minimum level over all phantoms of the highest different level with respect to node
// This is equivalent to min_{∀ source, target} partition.GetQueryLevel(source, node, target)
auto result = min_level(phantom_nodes[phantom_index]);
for (const auto &index : phantom_indices)
{
result = std::min(result, min_level(phantom_nodes[index]));
}
return result;
}
template <bool DIRECTION, typename... Args>
void relaxOutgoingEdges(const DataFacade<mld::Algorithm> &facade,
const NodeID node,
const EdgeWeight weight,
const EdgeDuration duration,
typename SearchEngineData<mld::Algorithm>::ManyToManyQueryHeap &query_heap,
const PhantomNode &phantom_node)
Args... args)
{
BOOST_ASSERT(!facade.ExcludeNode(node));
@@ -134,13 +182,7 @@ void relaxOutgoingEdges(const DataFacade<mld::Algorithm> &facade,
const auto &cells = facade.GetCellStorage();
const auto &metric = facade.GetCellMetric();
auto highest_diffrent_level = [&partition, node](const SegmentID &phantom_node) {
if (phantom_node.enabled)
return partition.GetHighestDifferentLevel(phantom_node.id, node);
return INVALID_LEVEL_ID;
};
const auto level = std::min(highest_diffrent_level(phantom_node.forward_segment_id),
highest_diffrent_level(phantom_node.reverse_segment_id));
const auto level = getNodeQueryLevel(partition, node, args...);
const auto &node_data = query_heap.GetData(node);
@@ -165,7 +207,8 @@ void relaxOutgoingEdges(const DataFacade<mld::Algorithm> &facade,
{
query_heap.Insert(to, to_weight, {node, true, to_duration});
}
else if (to_weight < query_heap.GetKey(to))
else if (std::tie(to_weight, to_duration) <
std::tie(query_heap.GetKey(to), query_heap.GetData(to).duration))
{
query_heap.GetData(to) = {node, true, to_duration};
query_heap.DecreaseKey(to, to_weight);
@@ -194,7 +237,8 @@ void relaxOutgoingEdges(const DataFacade<mld::Algorithm> &facade,
{
query_heap.Insert(to, to_weight, {node, true, to_duration});
}
else if (to_weight < query_heap.GetKey(to))
else if (std::tie(to_weight, to_duration) <
std::tie(query_heap.GetKey(to), query_heap.GetData(to).duration))
{
query_heap.GetData(to) = {node, true, to_duration};
query_heap.DecreaseKey(to, to_weight);
@@ -231,7 +275,8 @@ void relaxOutgoingEdges(const DataFacade<mld::Algorithm> &facade,
query_heap.Insert(to, to_weight, {node, false, to_duration});
}
// Found a shorter Path -> Update weight
else if (to_weight < query_heap.GetKey(to))
else if (std::tie(to_weight, to_duration) <
std::tie(query_heap.GetKey(to), query_heap.GetData(to).duration))
{
// new parent
query_heap.GetData(to) = {node, false, to_duration};
@@ -282,7 +327,7 @@ void forwardRoutingStep(const DataFacade<Algorithm> &facade,
current_duration = std::min(current_duration, new_duration);
}
}
else if (new_weight < current_weight)
else if (std::tie(new_weight, new_duration) < std::tie(current_weight, current_duration))
{
current_weight = new_weight;
current_duration = new_duration;
@@ -313,11 +358,11 @@ void backwardRoutingStep(const DataFacade<Algorithm> &facade,
}
template <typename Algorithm>
std::vector<EdgeWeight> manyToManySearch(SearchEngineData<Algorithm> &engine_working_data,
const DataFacade<Algorithm> &facade,
const std::vector<PhantomNode> &phantom_nodes,
std::vector<std::size_t> source_indices,
std::vector<std::size_t> target_indices)
std::vector<EdgeDuration> manyToManySearch(SearchEngineData<Algorithm> &engine_working_data,
const DataFacade<Algorithm> &facade,
const std::vector<PhantomNode> &phantom_nodes,
std::vector<std::size_t> source_indices,
std::vector<std::size_t> target_indices)
{
if (source_indices.empty())
{
@@ -406,20 +451,205 @@ std::vector<EdgeWeight> manyToManySearch(SearchEngineData<Algorithm> &engine_wor
return durations_table;
}
template std::vector<EdgeWeight>
template std::vector<EdgeDuration>
manyToManySearch(SearchEngineData<ch::Algorithm> &engine_working_data,
const DataFacade<ch::Algorithm> &facade,
const std::vector<PhantomNode> &phantom_nodes,
std::vector<std::size_t> source_indices,
std::vector<std::size_t> target_indices);
template std::vector<EdgeWeight>
template std::vector<EdgeDuration>
manyToManySearch(SearchEngineData<mld::Algorithm> &engine_working_data,
const DataFacade<mld::Algorithm> &facade,
const std::vector<PhantomNode> &phantom_nodes,
std::vector<std::size_t> source_indices,
std::vector<std::size_t> target_indices);
namespace mld
{
// Unidirectional multi-layer Dijkstra search for 1-to-N and N-to-1 matrices
template <bool DIRECTION>
std::vector<EdgeDuration> oneToManySearch(SearchEngineData<Algorithm> &engine_working_data,
const DataFacade<Algorithm> &facade,
const std::vector<PhantomNode> &phantom_nodes,
std::size_t phantom_index,
std::vector<std::size_t> phantom_indices)
{
if (phantom_indices.empty())
{
phantom_indices.resize(phantom_nodes.size());
std::iota(phantom_indices.begin(), phantom_indices.end(), 0);
}
std::vector<EdgeWeight> weights(phantom_indices.size(), INVALID_EDGE_WEIGHT);
std::vector<EdgeDuration> durations(phantom_indices.size(), MAXIMAL_EDGE_DURATION);
// Collect destination (source) nodes into a map
std::unordered_multimap<NodeID, std::tuple<std::size_t, EdgeWeight, EdgeDuration>>
target_nodes_index;
target_nodes_index.reserve(phantom_indices.size());
for (std::size_t index = 0; index < phantom_indices.size(); ++index)
{
const auto &phantom_index = phantom_indices[index];
const auto &phantom_node = phantom_nodes[phantom_index];
if (DIRECTION == FORWARD_DIRECTION)
{
if (phantom_node.IsValidForwardTarget())
target_nodes_index.insert(
{phantom_node.forward_segment_id.id,
std::make_tuple(index,
phantom_node.GetForwardWeightPlusOffset(),
phantom_node.GetForwardDuration())});
if (phantom_node.IsValidReverseTarget())
target_nodes_index.insert(
{phantom_node.reverse_segment_id.id,
std::make_tuple(index,
phantom_node.GetReverseWeightPlusOffset(),
phantom_node.GetReverseDuration())});
}
else if (DIRECTION == REVERSE_DIRECTION)
{
if (phantom_node.IsValidForwardSource())
target_nodes_index.insert(
{phantom_node.forward_segment_id.id,
std::make_tuple(index,
-phantom_node.GetForwardWeightPlusOffset(),
-phantom_node.GetForwardDuration())});
if (phantom_node.IsValidReverseSource())
target_nodes_index.insert(
{phantom_node.reverse_segment_id.id,
std::make_tuple(index,
-phantom_node.GetReverseWeightPlusOffset(),
-phantom_node.GetReverseDuration())});
}
}
// Initialize query heap
engine_working_data.InitializeOrClearManyToManyThreadLocalStorage(facade.GetNumberOfNodes());
auto &query_heap = *(engine_working_data.many_to_many_heap);
// Check if node is in the destinations list and update weights/durations
auto update_values = [&](NodeID node, EdgeWeight weight, EdgeDuration duration) {
auto candidates = target_nodes_index.equal_range(node);
for (auto it = candidates.first; it != candidates.second;)
{
std::size_t index;
EdgeWeight target_weight;
EdgeDuration target_duration;
std::tie(index, target_weight, target_duration) = it->second;
const auto path_weight = weight + target_weight;
if (path_weight >= 0)
{
const auto path_duration = duration + target_duration;
if (std::tie(path_weight, path_duration) <
std::tie(weights[index], durations[index]))
{
weights[index] = path_weight;
durations[index] = path_duration;
}
// Remove node from destinations list
it = target_nodes_index.erase(it);
}
else
{
++it;
}
}
};
// Check a single path result and insert adjacent nodes into heap
auto insert_node = [&](NodeID node, EdgeWeight initial_weight, EdgeDuration initial_duration) {
// Update single node paths
update_values(node, initial_weight, initial_duration);
// Place adjacent nodes into heap
for (auto edge : facade.GetAdjacentEdgeRange(node))
{
const auto &data = facade.GetEdgeData(edge);
if (DIRECTION == FORWARD_DIRECTION ? data.forward : data.backward)
{
query_heap.Insert(facade.GetTarget(edge),
data.weight + initial_weight,
{node, data.duration + initial_duration});
}
}
};
{ // Place source (destination) adjacent nodes into the heap
const auto &phantom_node = phantom_nodes[phantom_index];
if (DIRECTION == FORWARD_DIRECTION)
{
if (phantom_node.IsValidForwardSource())
insert_node(phantom_node.forward_segment_id.id,
-phantom_node.GetForwardWeightPlusOffset(),
-phantom_node.GetForwardDuration());
if (phantom_node.IsValidReverseSource())
insert_node(phantom_node.reverse_segment_id.id,
-phantom_node.GetReverseWeightPlusOffset(),
-phantom_node.GetReverseDuration());
}
else if (DIRECTION == REVERSE_DIRECTION)
{
if (phantom_node.IsValidForwardTarget())
insert_node(phantom_node.forward_segment_id.id,
phantom_node.GetForwardWeightPlusOffset(),
phantom_node.GetForwardDuration());
if (phantom_node.IsValidReverseTarget())
insert_node(phantom_node.reverse_segment_id.id,
phantom_node.GetReverseWeightPlusOffset(),
phantom_node.GetReverseDuration());
}
}
while (!query_heap.Empty() && !target_nodes_index.empty())
{
// Extract node from the heap
const auto node = query_heap.DeleteMin();
const auto weight = query_heap.GetKey(node);
const auto duration = query_heap.GetData(node).duration;
// Update values
update_values(node, weight, duration);
// Relax outgoing edges
relaxOutgoingEdges<DIRECTION>(facade,
node,
weight,
duration,
query_heap,
phantom_nodes,
phantom_index,
phantom_indices);
}
return durations;
}
template std::vector<EdgeDuration>
oneToManySearch<FORWARD_DIRECTION>(SearchEngineData<Algorithm> &engine_working_data,
const DataFacade<Algorithm> &facade,
const std::vector<PhantomNode> &phantom_nodes,
std::size_t phantom_index,
std::vector<std::size_t> phantom_indices);
template std::vector<EdgeDuration>
oneToManySearch<REVERSE_DIRECTION>(SearchEngineData<Algorithm> &engine_working_data,
const DataFacade<Algorithm> &facade,
const std::vector<PhantomNode> &phantom_nodes,
std::size_t phantom_index,
std::vector<std::size_t> phantom_indices);
} // mld
} // namespace routing_algorithms
} // namespace engine
} // namespace osrm
+25 -12
View File
@@ -287,23 +287,36 @@ void ExtractorCallbacks::ProcessWay(const osmium::Way &input_way, const Extracti
return lane_description;
};
// convert the lane description into an ID and, if necessary, remember the description in the
// description_map
const auto requestId = [&](const std::string &lane_string) {
if (lane_string.empty())
return INVALID_LANE_DESCRIPTIONID;
TurnLaneDescription lane_description = laneStringToDescription(std::move(lane_string));
return lane_description_map.ConcurrentFindOrAdd(lane_description);
};
// If we could parse turn lanes but could not parse number of lanes,
// count the turn lanes and use them for the way's number of lanes.
auto road_classification = parsed_way.road_classification;
std::uint8_t road_deduced_num_lanes = 0;
// Deduplicates street names, refs, destinations, pronunciation, exits.
// In case we do not already store the key, inserts (key, id) tuple and return id.
// Otherwise fetches the id based on the name and returns it without insertion.
const auto turn_lane_id_forward = requestId(parsed_way.turn_lanes_forward);
const auto turn_lane_id_backward = requestId(parsed_way.turn_lanes_backward);
auto turn_lane_id_forward = INVALID_LANE_DESCRIPTIONID;
auto turn_lane_id_backward = INVALID_LANE_DESCRIPTIONID;
const auto road_classification = parsed_way.road_classification;
// RoadClassification represents a the class for unidirectional ways,
// therefore we need to add up deduced forward and backward lane counts.
if (!parsed_way.turn_lanes_forward.empty())
{
auto desc = laneStringToDescription(parsed_way.turn_lanes_forward);
turn_lane_id_forward = lane_description_map.ConcurrentFindOrAdd(desc);
road_deduced_num_lanes += desc.size();
}
if (!parsed_way.turn_lanes_backward.empty())
{
auto desc = laneStringToDescription(parsed_way.turn_lanes_backward);
turn_lane_id_backward = lane_description_map.ConcurrentFindOrAdd(desc);
road_deduced_num_lanes += desc.size();
}
road_classification.SetNumberOfLanes(std::max(road_deduced_num_lanes, // len(turn:lanes)
road_classification.GetNumberOfLanes()));
// Get the unique identifier for the street name, destination, and ref
const auto name_iterator = string_map.find(MapKey(parsed_way.name,
+31
View File
@@ -0,0 +1,31 @@
#ifdef GLIBC_WORKAROUND
#include <stdexcept>
// https://github.com/bitcoin/bitcoin/pull/4042
// allows building against libstdc++-dev-4.9 while avoiding
// GLIBCXX_3.4.20 dep
// This is needed because libstdc++ itself uses this API - its not
// just an issue of your code using it, ughhh
// Note: only necessary on Linux
#ifdef __linux__
#define _ENABLE_GLIBC_WORKAROUND
#warning building with workaround
#else
#warning not building with workaround
#endif
#ifdef _ENABLE_GLIBC_WORKAROUND
namespace std
{
void __throw_out_of_range_fmt(const char *, ...) __attribute__((__noreturn__));
void __throw_out_of_range_fmt(const char *err, ...)
{
// Safe and over-simplified version. Ignore the format and print it as-is.
__throw_out_of_range(err);
}
}
#endif // _ENABLE_GLIBC_WORKAROUND
#endif // GLIBC_WORKAROUND
+26 -24
View File
@@ -144,30 +144,32 @@
{"key": "maxspeed", "value": "rural"},
{"key": "maxspeed", "value": "trunk"},
{"key": "maxspeed", "value": "motorway"},
{"key": "maxspeed", "value": "ch:rural"},
{"key": "maxspeed", "value": "ch:trunk"},
{"key": "maxspeed", "value": "ch:motorway"},
{"key": "maxspeed", "value": "de:living_street"},
{"key": "maxspeed", "value": "ru:living_street"},
{"key": "maxspeed", "value": "ru:urban"},
{"key": "maxspeed", "value": "ua:urban"},
{"key": "maxspeed", "value": "at:rural"},
{"key": "maxspeed", "value": "de:rural"},
{"key": "maxspeed", "value": "dk:rural"},
{"key": "maxspeed", "value": "at:trunk"},
{"key": "maxspeed", "value": "cz:trunk"},
{"key": "maxspeed", "value": "ro:trunk"},
{"key": "maxspeed", "value": "cz:motorway"},
{"key": "maxspeed", "value": "de:motorway"},
{"key": "maxspeed", "value": "ru:motorway"},
{"key": "maxspeed", "value": "gb:nsl_single"},
{"key": "maxspeed", "value": "gb:nsl_dual"},
{"key": "maxspeed", "value": "gb:motorway"},
{"key": "maxspeed", "value": "uk:nsl_single"},
{"key": "maxspeed", "value": "uk:nsl_dual"},
{"key": "maxspeed", "value": "uk:motorway"},
{"key": "maxspeed", "value": "nl:rural"},
{"key": "maxspeed", "value": "nl:trunk"},
{"key": "maxspeed", "value": "BE:motorway"},
{"key": "maxspeed", "value": "CH:rural"},
{"key": "maxspeed", "value": "CH:trunk"},
{"key": "maxspeed", "value": "CH:motorway"},
{"key": "maxspeed", "value": "DE:living_street"},
{"key": "maxspeed", "value": "DK:rural"},
{"key": "maxspeed", "value": "RU:living_street"},
{"key": "maxspeed", "value": "RU:urban"},
{"key": "maxspeed", "value": "UA:urban"},
{"key": "maxspeed", "value": "AT:rural"},
{"key": "maxspeed", "value": "DE:rural"},
{"key": "maxspeed", "value": "DK:rural"},
{"key": "maxspeed", "value": "AT:trunk"},
{"key": "maxspeed", "value": "CZ:trunk"},
{"key": "maxspeed", "value": "RO:trunk"},
{"key": "maxspeed", "value": "CZ:motorway"},
{"key": "maxspeed", "value": "DE:motorway"},
{"key": "maxspeed", "value": "RU:motorway"},
{"key": "maxspeed", "value": "GB:nsl_single"},
{"key": "maxspeed", "value": "GB:nsl_dual"},
{"key": "maxspeed", "value": "GB:motorway"},
{"key": "maxspeed", "value": "UK:nsl_single"},
{"key": "maxspeed", "value": "UK:nsl_dual"},
{"key": "maxspeed", "value": "UK:motorway"},
{"key": "maxspeed", "value": "NL:rural"},
{"key": "maxspeed", "value": "NL:trunk"},
{"key": "smoothness", "value": "intermediate"},
{"key": "smoothness", "value": "bad"},
{"key": "smoothness", "value": "very_bad"},