Compare commits
24 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
| ca464fcd5d | |||
| e9b7b68427 | |||
| 6b8ae24df6 | |||
| 65385b55e9 | |||
| f20dda55c0 | |||
| ff7f8557e3 | |||
| eff1d4e622 | |||
| f82908d509 | |||
| b3b6e16940 | |||
| f9fb0b84a8 | |||
| 83acb46390 | |||
| f36b3fb4bc | |||
| e7be271c43 | |||
| 790b574114 | |||
| b3f59ab92c | |||
| f2333eb31a | |||
| a862e5fb3a | |||
| 2715e5758b | |||
| 454487dd41 | |||
| 2ed4f6eb0c | |||
| d7bcafcb59 | |||
| c37a8ddd83 | |||
| fc3f96abcb | |||
| c37ea441fc |
+19
-14
@@ -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}
|
||||
|
||||
@@ -6,6 +6,8 @@
|
||||
- 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
|
||||
|
||||
+10
-7
@@ -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")
|
||||
|
||||
@@ -60,7 +61,7 @@ if (POLICY CMP0048)
|
||||
endif()
|
||||
project(OSRM C CXX)
|
||||
set(OSRM_VERSION_MAJOR 5)
|
||||
set(OSRM_VERSION_MINOR 12)
|
||||
set(OSRM_VERSION_MINOR 13)
|
||||
set(OSRM_VERSION_PATCH 0)
|
||||
set(OSRM_VERSION "${OSRM_VERSION_MAJOR}.${OSRM_VERSION_MINOR}.${OSRM_VERSION_PATCH}")
|
||||
|
||||
@@ -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()
|
||||
|
||||
@@ -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
@@ -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.
|
||||
|
||||
@@ -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
@@ -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
|
||||
|
||||
@@ -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.
|
||||
|
||||
@@ -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) => {
|
||||
|
||||
@@ -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 |
|
||||
|
||||
@@ -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};
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -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
@@ -1,6 +1,6 @@
|
||||
{
|
||||
"name": "osrm",
|
||||
"version": "5.12.0-roundaboutexits.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": {
|
||||
|
||||
@@ -250,6 +250,7 @@ function setup()
|
||||
|
||||
-- List only exceptions
|
||||
maxspeed_table = {
|
||||
["be:motorway"] = 120,
|
||||
["ch:rural"] = 80,
|
||||
["ch:trunk"] = 100,
|
||||
["ch:motorway"] = 120,
|
||||
|
||||
@@ -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
@@ -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" >' \
|
||||
+ '🚦 ' + 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))
|
||||
|
||||
@@ -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
|
||||
@@ -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
|
||||
@@ -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
|
||||
|
||||
@@ -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,
|
||||
|
||||
@@ -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
@@ -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"},
|
||||
|
||||
Reference in New Issue
Block a user