Compare commits
60 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
| c5167d4ade | |||
| 1548803a77 | |||
| 2b2906f97a | |||
| ca464fcd5d | |||
| e9b7b68427 | |||
| 6b8ae24df6 | |||
| 65385b55e9 | |||
| f20dda55c0 | |||
| ff7f8557e3 | |||
| eff1d4e622 | |||
| f82908d509 | |||
| b3b6e16940 | |||
| f9fb0b84a8 | |||
| 83acb46390 | |||
| f36b3fb4bc | |||
| e7be271c43 | |||
| 790b574114 | |||
| b3f59ab92c | |||
| f2333eb31a | |||
| a862e5fb3a | |||
| 2715e5758b | |||
| 454487dd41 | |||
| 2ed4f6eb0c | |||
| d7bcafcb59 | |||
| c37a8ddd83 | |||
| fc3f96abcb | |||
| c37ea441fc | |||
| fa1a4e8bf6 | |||
| 2532d56b85 | |||
| 00fd869224 | |||
| 5661726e2e | |||
| cfa5d7e172 | |||
| fd7791a0e2 | |||
| e32b8bae00 | |||
| 966139cde9 | |||
| ee19383f4d | |||
| 172a8bdcdb | |||
| 543048efcc | |||
| 67c85ffa4c | |||
| c065335882 | |||
| f6313fcbfb | |||
| 6a3ea876b5 | |||
| 64ad308e9d | |||
| 94169a20de | |||
| 5ca38eee3a | |||
| f4f65f62ee | |||
| f89ada7f61 | |||
| ff3b398e23 | |||
| 84cb7865ab | |||
| 75bdf114be | |||
| c2fd64d3cc | |||
| 580c5e39ae | |||
| 8da6281dcd | |||
| f79bcc6b8d | |||
| f2b63ba0aa | |||
| a253111cbe | |||
| a5776288f6 | |||
| dbcf4cab16 | |||
| 4ea3f33376 | |||
| e4cdfb50cd |
+27
-22
@@ -68,7 +68,7 @@ matrix:
|
||||
addons: &gcc6
|
||||
apt:
|
||||
sources: ['ubuntu-toolchain-r-test']
|
||||
packages: ['g++-6', 'libbz2-dev', 'libxml2-dev', 'libzip-dev', 'lua5.1', 'liblua5.1-0-dev', 'libtbb-dev', 'libgdal-dev', 'libboost-all-dev']
|
||||
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' ENABLE_COVERAGE=ON CUCUMBER_TIMEOUT=20000
|
||||
after_success:
|
||||
- bash <(curl -s https://codecov.io/bash)
|
||||
@@ -78,15 +78,15 @@ matrix:
|
||||
addons: &gcc6
|
||||
apt:
|
||||
sources: ['ubuntu-toolchain-r-test']
|
||||
packages: ['g++-6', 'libbz2-dev', 'libxml2-dev', 'libzip-dev', 'lua5.1', 'liblua5.1-0-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
|
||||
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 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', 'lua5.1', 'liblua5.1-0-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
|
||||
@@ -111,7 +111,7 @@ matrix:
|
||||
addons: &gcc6
|
||||
apt:
|
||||
sources: ['ubuntu-toolchain-r-test']
|
||||
packages: ['g++-6', 'libbz2-dev', 'libxml2-dev', 'libzip-dev', 'lua5.1', 'liblua5.1-0-dev', 'libtbb-dev', 'libgdal-dev', 'libboost-all-dev']
|
||||
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='Release'
|
||||
|
||||
- os: linux
|
||||
@@ -125,7 +125,7 @@ matrix:
|
||||
addons: &gcc6
|
||||
apt:
|
||||
sources: ['ubuntu-toolchain-r-test']
|
||||
packages: ['g++-6', 'libbz2-dev', 'libstxxl-dev', 'libxml2-dev', 'libzip-dev', 'lua5.1', 'liblua5.1-0-dev', 'libtbb-dev', 'libgdal-dev', 'libboost-all-dev']
|
||||
packages: ['g++-6', 'libbz2-dev', 'libstxxl-dev', 'libxml2-dev', 'libzip-dev', 'liblua5.2-dev', 'libtbb-dev', 'libgdal-dev', 'libboost-all-dev']
|
||||
env: CCOMPILER='gcc-6' CXXCOMPILER='g++-6' BUILD_TYPE='Release' ENABLE_STXXL=On
|
||||
|
||||
- os: linux
|
||||
@@ -133,7 +133,7 @@ matrix:
|
||||
addons: &gcc49
|
||||
apt:
|
||||
sources: ['ubuntu-toolchain-r-test']
|
||||
packages: ['g++-4.9', 'libbz2-dev', 'libxml2-dev', 'libzip-dev', 'lua5.1', 'liblua5.1-0-dev', 'libtbb-dev', 'libgdal-dev', 'libluabind-dev', 'libboost-all-dev', 'ccache']
|
||||
packages: ['g++-4.9', 'libbz2-dev', 'libxml2-dev', 'libzip-dev', 'liblua5.2-dev', 'libtbb-dev', 'libgdal-dev', 'libboost-all-dev', 'ccache']
|
||||
env: CCOMPILER='gcc-4.9' CXXCOMPILER='g++-4.9' BUILD_TYPE='Release'
|
||||
|
||||
- os: osx
|
||||
@@ -158,7 +158,7 @@ matrix:
|
||||
#- addons: &clang40
|
||||
#- apt:
|
||||
#- sources: ['llvm-toolchain-trusty-4.0', 'ubuntu-toolchain-r-test']
|
||||
#- packages: ['clang-4.0', 'libbz2-dev', 'libxml2-dev', 'libzip-dev', 'lua5.1', 'liblua5.1-0-dev', 'libtbb-dev', 'libgdal-dev', 'libboost-all-dev']
|
||||
#- packages: ['clang-4.0', 'libbz2-dev', 'libxml2-dev', 'libzip-dev', 'liblua5.2-dev', 'libtbb-dev', 'libgdal-dev', 'libboost-all-dev']
|
||||
#- env: CCOMPILER='clang-4.0' CXXCOMPILER='clang++-4.0' BUILD_TYPE='Release'
|
||||
|
||||
# Shared Library
|
||||
@@ -167,7 +167,7 @@ matrix:
|
||||
addons: &gcc6
|
||||
apt:
|
||||
sources: ['ubuntu-toolchain-r-test']
|
||||
packages: ['g++-6', 'libbz2-dev', 'libxml2-dev', 'libzip-dev', 'lua5.1', 'liblua5.1-0-dev', 'libtbb-dev', 'libgdal-dev', 'libboost-all-dev']
|
||||
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='Release' BUILD_SHARED_LIBS=ON
|
||||
|
||||
# Disabled because CI slowness
|
||||
@@ -176,7 +176,7 @@ matrix:
|
||||
#- addons: &clang40
|
||||
#- apt:
|
||||
#- sources: ['llvm-toolchain-trusty-4.0', 'ubuntu-toolchain-r-test']
|
||||
#- packages: ['clang-4.0', 'libbz2-dev', 'libxml2-dev', 'libzip-dev', 'lua5.1', 'liblua5.1-0-dev', 'libtbb-dev', 'libgdal-dev', 'libboost-all-dev']
|
||||
#- packages: ['clang-4.0', 'libbz2-dev', 'libxml2-dev', 'libzip-dev', 'liblua5.2-dev', 'libtbb-dev', 'libgdal-dev', 'libboost-all-dev']
|
||||
#- env: CCOMPILER='clang-4.0' CXXCOMPILER='clang++-4.0' BUILD_TYPE='Release' BUILD_SHARED_LIBS=ON
|
||||
|
||||
# Node build jobs. These skip running the tests.
|
||||
@@ -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}
|
||||
|
||||
@@ -1,4 +1,15 @@
|
||||
# UNRELEASED
|
||||
- Profile:
|
||||
- New function to support relations: `process_relation`. Read more in profiles documentation.
|
||||
- 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
|
||||
- now announcing turning onto oneways at the end of a road (e.g. onto dual carriageways)
|
||||
- Adds new instruction types at the exit of roundabouts and rotaries `exit roundabout` and `exit rotary`.
|
||||
|
||||
+13
-27
@@ -31,12 +31,13 @@ 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")
|
||||
|
||||
if(ENABLE_MASON)
|
||||
# versions in use
|
||||
set(MASON_BOOST_VERSION "1.63.0")
|
||||
set(MASON_BOOST_VERSION "1.65.1")
|
||||
set(MASON_STXXL_VERSION "1.4.1-1")
|
||||
set(MASON_EXPAT_VERSION "2.2.0")
|
||||
set(MASON_LUA_VERSION "5.2.4")
|
||||
@@ -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}")
|
||||
|
||||
@@ -379,8 +380,8 @@ set(CMAKE_MODULE_LINKER_FLAGS "${CMAKE_MODULE_LINKER_FLAGS} ${LINKER_FLAGS}")
|
||||
|
||||
# Activate C++1y
|
||||
if(NOT CMAKE_CXX_COMPILER_ID MATCHES "MSVC")
|
||||
set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -std=c++1y")
|
||||
set(OSRM_CXXFLAGS "${OSRM_CXXFLAGS} -std=c++1y")
|
||||
set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -std=c++14")
|
||||
set(OSRM_CXXFLAGS "${OSRM_CXXFLAGS} -std=c++14")
|
||||
endif()
|
||||
|
||||
# Configuring other platform dependencies
|
||||
@@ -517,29 +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()
|
||||
FIND_PACKAGE(Lua 5.1 EXACT)
|
||||
IF (LUA_FOUND)
|
||||
MESSAGE(STATUS "Using Lua ${LUA_VERSION_STRING}")
|
||||
ELSE()
|
||||
# Now fall back to a lua verison without exact
|
||||
# in case this cmake version also forces patch versions
|
||||
FIND_PACKAGE(Lua 5.2)
|
||||
IF (LUA_FOUND)
|
||||
MESSAGE(STATUS "Using Lua ${LUA_VERSION_STRING}")
|
||||
ELSE()
|
||||
FIND_PACKAGE(Lua 5.1)
|
||||
IF (LUA_FOUND)
|
||||
MESSAGE(STATUS "Using Lua ${LUA_VERSION_STRING}")
|
||||
ELSE()
|
||||
MESSAGE(FATAL_ERROR "Lua 5.1 or 5.2 was not found.")
|
||||
ENDIF()
|
||||
ENDIF()
|
||||
ENDIF()
|
||||
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})
|
||||
@@ -829,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
|
||||
|
||||
+8
-5
@@ -7,19 +7,22 @@ ECHO ~~~~~~~~~~~~~~~~~~~~~~~~~~~~ %~f0 ~~~~~~~~~~~~~~~~~~~~~~~~~~~~
|
||||
SET PROJECT_DIR=%CD%
|
||||
ECHO PROJECT_DIR^: %PROJECT_DIR%
|
||||
ECHO NUMBER_OF_PROCESSORS^: %NUMBER_OF_PROCESSORS%
|
||||
|
||||
|
||||
:: Check CMake version
|
||||
SET CMAKE_VERSION=3.9.2
|
||||
SET PATH=%PROJECT_DIR%\cmake-%CMAKE_VERSION%-win32-x86\bin;%PATH%
|
||||
ECHO cmake^: && cmake --version
|
||||
IF %ERRORLEVEL% NEQ 0 ECHO CMAKE not found && GOTO CMAKE_NOT_OK
|
||||
|
||||
cmake --version | findstr /C:"3.7.1" && GOTO CMAKE_OK
|
||||
cmake --version | findstr /C:%CMAKE_VERSION% && GOTO CMAKE_OK
|
||||
|
||||
:CMAKE_NOT_OK
|
||||
SET CMAKE_VERSION=3.7.1
|
||||
ECHO CMAKE NOT OK - downloading new CMake %CMAKE_VERSION%
|
||||
IF NOT EXIST cm.zip powershell Invoke-WebRequest https://cmake.org/files/v3.7/cmake-%CMAKE_VERSION%-win32-x86.zip -OutFile $env:PROJECT_DIR\cm.zip
|
||||
powershell Invoke-WebRequest https://cmake.org/files/v3.9/cmake-%CMAKE_VERSION%-win32-x86.zip -OutFile $env:PROJECT_DIR\cm.zip
|
||||
IF %ERRORLEVEL% NEQ 0 GOTO ERROR
|
||||
IF NOT EXIST cmake-%CMAKE_VERSION%-win32-x86 7z -y x cm.zip | %windir%\system32\FIND "ing archive"
|
||||
IF %ERRORLEVEL% NEQ 0 GOTO ERROR
|
||||
SET PATH=%PROJECT_DIR%\cmake-%CMAKE_VERSION%-win32-x86\bin;%PATH%
|
||||
|
||||
:CMAKE_OK
|
||||
ECHO CMAKE_OK
|
||||
@@ -37,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
|
||||
|
||||
+60
-8
@@ -47,7 +47,7 @@ Profiles can also define a `process_segment` function to handle differences in s
|
||||
|
||||
At the end of the file, a table if returned with references to the setup and processing functions the profile has defined.
|
||||
|
||||
## Understanding speed, weight and rate
|
||||
## Understanding speed, weight and rate
|
||||
When computing a route from A to B there can be different measure of what is the best route. That's why there's a need for different profiles.
|
||||
|
||||
Because speeds very on different types of roads, the shortest and the fastest route are typically different. But there are many other possible preferences. For example a user might prefer a bicycle route that follow parks or other green areas, even though both duration and distance are a bit longer.
|
||||
@@ -91,7 +91,7 @@ The `setup` function is called once when the profile is loaded and must return a
|
||||
|
||||
Note that processing of data is parallelized and several unconnected LUA interpreters will be running at the same time. The `setup` function will be called once for each. Each LUA iinterpreter will have it's own set of globals.
|
||||
|
||||
The following global properties can be set under `properties` in the hash you return in the `setup` function:
|
||||
The following global properties can be set under `properties` in the hash you return in the `setup` function:
|
||||
|
||||
Attribute | Type | Notes
|
||||
-------------------------------------|----------|----------------------------------------------------------------------------
|
||||
@@ -114,7 +114,7 @@ classes | Sequence | Determines the allowed
|
||||
restrictions | Sequence | Determines which turn restrictions will be used for this profile.
|
||||
suffix_list | Set | List of name suffixes needed for determining if "Highway 101 NW" the same road as "Highway 101 ES".
|
||||
|
||||
### process_node(profile, node, result)
|
||||
### process_node(profile, node, result, relations)
|
||||
Process an OSM node to determine whether this node is a barrier or can be passed and whether passing it incurs a delay.
|
||||
|
||||
Argument | Description
|
||||
@@ -122,6 +122,7 @@ Argument | Description
|
||||
profile | The configuration table you returned in `setup`.
|
||||
node | The input node to process (read-only).
|
||||
result | The output that you will modify.
|
||||
relations| The list of relation attributes passed from `process_relation` function for this node.
|
||||
|
||||
The following attributes can be set on `result`:
|
||||
|
||||
@@ -130,7 +131,7 @@ Attribute | Type | Notes
|
||||
barrier | Boolean | Is it an impassable barrier?
|
||||
traffic_lights | Boolean | Is it a traffic light (incurs delay in `process_turn`)?
|
||||
|
||||
## process_way(profile, way, result)
|
||||
### process_way(profile, way, result, relations)
|
||||
Given an OpenStreetMap way, the `process_way` function will either return nothing (meaning we are not going to route over this way at all), or it will set up a result hash.
|
||||
|
||||
Argument | Description
|
||||
@@ -138,6 +139,7 @@ Argument | Description
|
||||
profile | The configuration table you returned in `setup`.
|
||||
node | The input way to process (read-only).
|
||||
result | The output that you will modify.
|
||||
relations| The list of relation attributes passed from `process_relation` function for this way.
|
||||
|
||||
Importantly it will set `result.forward_mode` and `result.backward_mode` to indicate the travel mode in each direction, as well as set `result.forward_speed` and `result.backward_speed` to integer values representing the speed for traversing the way.
|
||||
|
||||
@@ -177,10 +179,60 @@ road_classification.road_priority_class | Enum | Guidance: order in priority
|
||||
road_classification.may_be_ignored | Boolean | Guidance: way is non-highway
|
||||
road_classification.num_lanes | Unsigned | Guidance: total number of lanes in way
|
||||
|
||||
### process_segment(profile, segment)
|
||||
The `process_segment` function is called for every segment of OSM ways. A segment is a straight line between two OSM nodes.
|
||||
### process_relation(profile, relation, result)
|
||||
|
||||
On OpenStreetMap way cannot have different tags on different parts of a way. Instead you would split the way into several smaller ways. However many ways are long. For example, many ways pass hills without any change in tags.
|
||||
Supported since API **version 3**.
|
||||
|
||||
Given an OpenStreetMap relation, the `process_relation` function should setup values into result structure.
|
||||
|
||||
Argument | Description
|
||||
---------|-------------------------------------------------------
|
||||
profile | The configuration table you returned in `setup`.
|
||||
node | The input relation to process (read-only).
|
||||
result | The output that you will modify.
|
||||
|
||||
Relation process work flow consist of next steps:
|
||||
1. Calls `process_relation` function for each relation. It should fill a `result` structure
|
||||
2. After that each data will be passed for each member of processed relation into `process_node` and `process_way` functions
|
||||
|
||||
The following attributes can be set on that result in `process_relation`:
|
||||
|
||||
Attribute | Type | Notes
|
||||
----------------------------------------|----------|--------------------------------------------------------------------------
|
||||
is_restriction | Boolean | Flag to determine if relation is a turn restriction
|
||||
|
||||
Example processing code:
|
||||
```lua
|
||||
|
||||
function process_way(profile, way, result, relations)
|
||||
for _, r in ipairs(relations) do
|
||||
for k, v in pairs(r) do
|
||||
print('data_' .. k .. '_value_' .. v)
|
||||
end
|
||||
end
|
||||
print ('process_way ' .. way:id() .. ' ' .. result.name)
|
||||
end
|
||||
|
||||
function process_relation(profile, relation, result)
|
||||
local t = relation:get_value_by_key("type")
|
||||
if t == "route" then
|
||||
for _, m in ipairs(relation:members()) do
|
||||
if m:role == "north" then
|
||||
result[m]['direction'] = 'north'
|
||||
print('direction_north')
|
||||
end
|
||||
end
|
||||
|
||||
print('route_relation')
|
||||
end
|
||||
end
|
||||
```
|
||||
|
||||
|
||||
### process_segment(profile, segment)
|
||||
The `process_segment` function is called for every segment of OSM ways. A segment is a straight line between two OSM nodes.
|
||||
|
||||
On OpenStreetMap way cannot have different tags on different parts of a way. Instead you would split the way into several smaller ways. However many ways are long. For example, many ways pass hills without any change in tags.
|
||||
|
||||
Processing each segment of an OSM way makes it possible to have different speeds on different parts of a way based on external data like data about elevation, pollution, noise or scenic value and adjust weight and duration of the segment.
|
||||
|
||||
@@ -265,7 +317,7 @@ Example:
|
||||
function process_segment (profile, segment)
|
||||
local sourceData = raster:query(profile.raster_source, segment.source.lon, segment.source.lat)
|
||||
local targetData = raster:query(profile.raster_source, segment.target.lon, segment.target.lat)
|
||||
|
||||
|
||||
local invalid = sourceData.invalid_data()
|
||||
if sourceData.datum ~= invalid and targetData.datum ~= invalid then
|
||||
-- use values to adjust weight and duration
|
||||
|
||||
@@ -0,0 +1,35 @@
|
||||
@routing @bicycle
|
||||
Feature: Bike - Use distance weight
|
||||
|
||||
Background:
|
||||
Given a grid size of 200 meters
|
||||
|
||||
Scenario: Bike - Check distance weight
|
||||
Given the profile file
|
||||
"""
|
||||
local functions = require('bicycle')
|
||||
functions.setup_testbot = functions.setup
|
||||
|
||||
functions.setup = function()
|
||||
local profile = functions.setup_testbot()
|
||||
profile.properties.weight_name = 'distance'
|
||||
return profile
|
||||
end
|
||||
|
||||
return functions
|
||||
"""
|
||||
|
||||
Given the node map
|
||||
"""
|
||||
a-b-c
|
||||
"""
|
||||
|
||||
|
||||
And the ways
|
||||
| nodes | highway |
|
||||
| abc | residential |
|
||||
|
||||
When I route I should get
|
||||
| from | to | route | weight | time | distance |
|
||||
| a | b | abc,abc | 200 | 48s | 200m +-1 |
|
||||
| a | c | abc,abc | 400 | 96s | 400m +-1 |
|
||||
@@ -0,0 +1,35 @@
|
||||
@routing @foot
|
||||
Feature: Foot - Use distance weight
|
||||
|
||||
Background:
|
||||
Given a grid size of 200 meters
|
||||
|
||||
Scenario: Foot - Check distance weight
|
||||
Given the profile file
|
||||
"""
|
||||
local functions = require('foot')
|
||||
functions.setup_testbot = functions.setup
|
||||
|
||||
functions.setup = function()
|
||||
local profile = functions.setup_testbot()
|
||||
profile.properties.weight_name = 'distance'
|
||||
return profile
|
||||
end
|
||||
|
||||
return functions
|
||||
"""
|
||||
|
||||
Given the node map
|
||||
"""
|
||||
a-b-c
|
||||
"""
|
||||
|
||||
|
||||
And the ways
|
||||
| nodes | highway |
|
||||
| abc | residential |
|
||||
|
||||
When I route I should get
|
||||
| from | to | route | weight | time | distance |
|
||||
| a | b | abc,abc | 200 | 144s | 200m +-1 |
|
||||
| a | c | abc,abc | 400 | 288s | 400m +-1 |
|
||||
@@ -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.
|
||||
|
||||
@@ -1349,3 +1349,24 @@ Feature: Simple Turns
|
||||
When I route I should get
|
||||
| waypoints | route | turns |
|
||||
| a,d | ab,dc,dc | depart,turn left,arrive |
|
||||
|
||||
|
||||
# https://www.openstreetmap.org/node/1332083066
|
||||
Scenario: Turns ordering must respect initial bearings
|
||||
Given the node map
|
||||
"""
|
||||
a . be .
|
||||
\ c.
|
||||
d/ .f . g
|
||||
"""
|
||||
|
||||
And the ways
|
||||
| nodes | highway | oneway |
|
||||
| ab | primary | yes |
|
||||
| bcd | primary | yes |
|
||||
| befg | primary | yes |
|
||||
|
||||
When I route I should get
|
||||
| waypoints | route | turns |
|
||||
| a,d | ab,bcd,bcd | depart,fork slight right,arrive |
|
||||
| a,g | ab,befg,befg | depart,fork slight left,arrive |
|
||||
|
||||
@@ -0,0 +1,32 @@
|
||||
@extract
|
||||
Feature: osrm-extract must be silent with NONE
|
||||
|
||||
Background:
|
||||
Given the node map
|
||||
"""
|
||||
a b
|
||||
"""
|
||||
And the ways
|
||||
| nodes |
|
||||
| ab |
|
||||
And the data has been saved to disk
|
||||
|
||||
Scenario: osrm-extract - Passing base file with verbosity NONE
|
||||
Given the profile file
|
||||
"""
|
||||
functions = require('testbot')
|
||||
|
||||
function way_function(profile, way, result)
|
||||
result.forward_mode = mode.driving
|
||||
result.forward_speed = 1
|
||||
end
|
||||
|
||||
functions.process_way = way_function
|
||||
return functions
|
||||
"""
|
||||
When I run "osrm-extract --profile {profile_file} {osm_file} --verbosity NONE"
|
||||
Then it should exit successfully
|
||||
And stdout should not contain "[info]"
|
||||
And stdout should not contain "[error]"
|
||||
And stdout should not contain "10%"
|
||||
And stderr should be empty
|
||||
@@ -24,7 +24,7 @@ Feature: Invalid profile API versions
|
||||
Scenario: Profile API version too high
|
||||
Given the profile file
|
||||
"""
|
||||
api_version = 3
|
||||
api_version = 4
|
||||
"""
|
||||
And the node map
|
||||
"""
|
||||
|
||||
@@ -0,0 +1,119 @@
|
||||
Feature: Profile API version 3
|
||||
|
||||
Background:
|
||||
Given a grid size of 100 meters
|
||||
|
||||
Scenario: Basic profile function calls and property values
|
||||
Given the profile file
|
||||
"""
|
||||
api_version = 3
|
||||
|
||||
Set = require('lib/set')
|
||||
Sequence = require('lib/sequence')
|
||||
Handlers = require("lib/way_handlers")
|
||||
find_access_tag = require("lib/access").find_access_tag
|
||||
limit = require("lib/maxspeed").limit
|
||||
|
||||
|
||||
function setup()
|
||||
return {
|
||||
properties = {
|
||||
max_speed_for_map_matching = 180/3.6,
|
||||
use_turn_restrictions = true,
|
||||
continue_straight_at_waypoint = true,
|
||||
weight_name = 'test_version2',
|
||||
weight_precision = 2
|
||||
}
|
||||
}
|
||||
end
|
||||
|
||||
function process_node(profile, node, result, relations)
|
||||
print ('process_node ' .. node:id())
|
||||
end
|
||||
|
||||
function process_way(profile, way, result, relations)
|
||||
result.name = way:get_value_by_key('name')
|
||||
result.weight = 10
|
||||
result.forward_mode = mode.driving
|
||||
result.backward_mode = mode.driving
|
||||
result.forward_speed = 36
|
||||
result.backward_speed = 36
|
||||
|
||||
for _, r in ipairs(relations) do
|
||||
for k, v in pairs(r) do
|
||||
print('data_' .. k .. '_value_' .. v)
|
||||
end
|
||||
end
|
||||
print ('process_way ' .. way:id() .. ' ' .. result.name)
|
||||
end
|
||||
|
||||
function process_relation(profile, relation, result)
|
||||
local t = relation:get_value_by_key("type")
|
||||
if t == "route" then
|
||||
for _, m in ipairs(relation:members()) do
|
||||
if m:role() == "north" then
|
||||
result[m]['direction'] = 'north'
|
||||
print('direction_north')
|
||||
end
|
||||
end
|
||||
|
||||
print('route_relation')
|
||||
end
|
||||
|
||||
print ('process_relation ' .. relation:id())
|
||||
end
|
||||
|
||||
function process_turn (profile, turn)
|
||||
print('process_turn', turn.angle, turn.turn_type, turn.direction_modifier, turn.has_traffic_light)
|
||||
turn.weight = turn.angle == 0 and 0 or 4.2
|
||||
turn.duration = turn.weight
|
||||
end
|
||||
|
||||
function process_segment (profile, segment)
|
||||
print ('process_segment ' .. segment.source.lon .. ' ' .. segment.source.lat)
|
||||
end
|
||||
|
||||
return {
|
||||
setup = setup,
|
||||
process_node = process_node,
|
||||
process_way = process_way,
|
||||
process_relation = process_relation,
|
||||
process_segment = process_segment,
|
||||
process_turn = process_turn
|
||||
}
|
||||
"""
|
||||
And the node map
|
||||
"""
|
||||
a
|
||||
bcd
|
||||
e
|
||||
"""
|
||||
And the ways
|
||||
| nodes |
|
||||
| ac |
|
||||
| cb |
|
||||
| cd |
|
||||
| ce |
|
||||
|
||||
And the relations
|
||||
| type | way:north | route |
|
||||
| route | ac | road |
|
||||
|
||||
And the data has been saved to disk
|
||||
|
||||
When I run "osrm-extract --profile {profile_file} {osm_file}"
|
||||
Then it should exit successfully
|
||||
And stdout should contain "process_relation"
|
||||
And stdout should contain "route_relation"
|
||||
And stdout should contain "direction_north"
|
||||
And stdout should contain "data_direction_value_north"
|
||||
And stdout should contain "process_node"
|
||||
And stdout should contain "process_way"
|
||||
And stdout should contain "process_turn"
|
||||
And stdout should contain "process_segment"
|
||||
|
||||
When I route I should get
|
||||
| from | to | route | time |
|
||||
| a | b | ac,cb,cb | 19.2s |
|
||||
| a | d | ac,cd,cd | 19.2s |
|
||||
| a | e | ac,ce | 20s |
|
||||
@@ -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};
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -24,6 +24,8 @@
|
||||
#include "util/fingerprint.hpp"
|
||||
#include "util/json_container.hpp"
|
||||
|
||||
#include <tbb/task_scheduler_init.h>
|
||||
|
||||
#include <memory>
|
||||
#include <string>
|
||||
|
||||
@@ -53,7 +55,8 @@ template <typename Algorithm> class Engine final : public EngineInterface
|
||||
{
|
||||
public:
|
||||
explicit Engine(const EngineConfig &config)
|
||||
: route_plugin(config.max_locations_viaroute, config.max_alternatives), //
|
||||
: task_scheduler(config.use_threads_number),
|
||||
route_plugin(config.max_locations_viaroute, config.max_alternatives), //
|
||||
table_plugin(config.max_locations_distance_table), //
|
||||
nearest_plugin(config.max_results_nearest), //
|
||||
trip_plugin(config.max_locations_trip), //
|
||||
@@ -125,6 +128,7 @@ template <typename Algorithm> class Engine final : public EngineInterface
|
||||
}
|
||||
std::unique_ptr<DataFacadeProvider<Algorithm>> facade_provider;
|
||||
mutable SearchEngineData<Algorithm> heaps;
|
||||
tbb::task_scheduler_init task_scheduler;
|
||||
|
||||
const plugins::ViaRoutePlugin route_plugin;
|
||||
const plugins::TablePlugin table_plugin;
|
||||
|
||||
@@ -90,6 +90,8 @@ struct EngineConfig final
|
||||
int max_alternatives = 3; // set an arbitrary upper bound; can be adjusted by user
|
||||
bool use_shared_memory = true;
|
||||
Algorithm algorithm = Algorithm::CH;
|
||||
int use_threads_number = 1;
|
||||
std::string verbosity;
|
||||
};
|
||||
}
|
||||
}
|
||||
|
||||
@@ -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,
|
||||
const std::vector<std::size_t> &source_indices,
|
||||
const 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
|
||||
|
||||
@@ -0,0 +1,81 @@
|
||||
#ifndef EXTRACTION_RELATION_HPP
|
||||
#define EXTRACTION_RELATION_HPP
|
||||
|
||||
#include <osmium/osm/relation.hpp>
|
||||
|
||||
#include <boost/assert.hpp>
|
||||
|
||||
#include <string>
|
||||
#include <unordered_map>
|
||||
#include <vector>
|
||||
|
||||
namespace osrm
|
||||
{
|
||||
namespace extractor
|
||||
{
|
||||
|
||||
struct ExtractionRelation
|
||||
{
|
||||
using AttributesMap = std::unordered_map<std::string, std::string>;
|
||||
using OsmIDTyped = std::pair<osmium::object_id_type, osmium::item_type>;
|
||||
|
||||
struct OsmIDTypedHash
|
||||
{
|
||||
std::size_t operator()(const OsmIDTyped &id) const
|
||||
{
|
||||
return id.first ^ (static_cast<std::uint64_t>(id.second) << 56);
|
||||
}
|
||||
};
|
||||
|
||||
ExtractionRelation() : is_restriction(false) {}
|
||||
|
||||
void clear()
|
||||
{
|
||||
is_restriction = false;
|
||||
values.clear();
|
||||
}
|
||||
|
||||
bool IsRestriction() const { return is_restriction; }
|
||||
|
||||
AttributesMap &GetMember(const osmium::RelationMember &member)
|
||||
{
|
||||
return values[OsmIDTyped(member.ref(), member.type())];
|
||||
}
|
||||
|
||||
bool is_restriction;
|
||||
std::unordered_map<OsmIDTyped, AttributesMap, OsmIDTypedHash> values;
|
||||
};
|
||||
|
||||
// It contains data of all parsed relations for each node/way element
|
||||
class ExtractionRelationContainer
|
||||
{
|
||||
public:
|
||||
using AttributesMap = ExtractionRelation::AttributesMap;
|
||||
using OsmIDTyped = ExtractionRelation::OsmIDTyped;
|
||||
using RelationList = std::vector<AttributesMap>;
|
||||
|
||||
void AddRelation(const ExtractionRelation &rel)
|
||||
{
|
||||
BOOST_ASSERT(!rel.is_restriction);
|
||||
for (auto it : rel.values)
|
||||
data[it.first].push_back(it.second);
|
||||
}
|
||||
|
||||
const RelationList &Get(const OsmIDTyped &id) const
|
||||
{
|
||||
const auto it = data.find(id);
|
||||
if (it != data.end())
|
||||
return it->second;
|
||||
|
||||
static RelationList empty;
|
||||
return empty;
|
||||
}
|
||||
|
||||
private:
|
||||
std::unordered_map<OsmIDTyped, RelationList, ExtractionRelation::OsmIDTypedHash> data;
|
||||
};
|
||||
|
||||
} // namespace extractor
|
||||
} // namespace osrm
|
||||
|
||||
#endif // EXTRACTION_RELATION_HPP
|
||||
@@ -15,6 +15,7 @@ namespace osmium
|
||||
{
|
||||
class Node;
|
||||
class Way;
|
||||
class Relation;
|
||||
}
|
||||
|
||||
namespace std
|
||||
@@ -44,6 +45,7 @@ namespace extractor
|
||||
class ExtractionContainers;
|
||||
struct ExtractionNode;
|
||||
struct ExtractionWay;
|
||||
struct ExtractionRelation;
|
||||
struct ProfileProperties;
|
||||
struct InputConditionalTurnRestriction;
|
||||
|
||||
|
||||
@@ -153,6 +153,14 @@ class CoordinateExtractor
|
||||
const double length,
|
||||
const double rate) const;
|
||||
|
||||
// find the coordinate at a specific distance in the vector
|
||||
util::Coordinate
|
||||
ExtractCoordinateAtLength(const double distance,
|
||||
const std::vector<util::Coordinate> &coordinates) const;
|
||||
util::Coordinate ExtractCoordinateAtLength(const double distance,
|
||||
const std::vector<util::Coordinate> &coordinates,
|
||||
const std::vector<double> &length_cache) const;
|
||||
|
||||
private:
|
||||
const util::NodeBasedDynamicGraph &node_based_graph;
|
||||
const extractor::CompressedEdgeContainer &compressed_geometries;
|
||||
@@ -241,14 +249,6 @@ class CoordinateExtractor
|
||||
const double segment_length,
|
||||
const std::vector<double> &segment_distances,
|
||||
const std::uint8_t considered_lanes) const;
|
||||
|
||||
// find the coordinate at a specific location in the vector
|
||||
util::Coordinate ExtractCoordinateAtLength(const double distance,
|
||||
const std::vector<util::Coordinate> &coordinates,
|
||||
const std::vector<double> &length_cache) const;
|
||||
util::Coordinate
|
||||
ExtractCoordinateAtLength(const double distance,
|
||||
const std::vector<util::Coordinate> &coordinates) const;
|
||||
};
|
||||
|
||||
} // namespace guidance
|
||||
|
||||
@@ -19,6 +19,7 @@ namespace osmium
|
||||
{
|
||||
class Node;
|
||||
class Way;
|
||||
class Relation;
|
||||
}
|
||||
|
||||
namespace osrm
|
||||
@@ -33,8 +34,10 @@ namespace extractor
|
||||
{
|
||||
|
||||
class RestrictionParser;
|
||||
class ExtractionRelationContainer;
|
||||
struct ExtractionNode;
|
||||
struct ExtractionWay;
|
||||
struct ExtractionRelation;
|
||||
struct ExtractionTurn;
|
||||
struct ExtractionSegment;
|
||||
|
||||
@@ -59,12 +62,14 @@ class ScriptingEnvironment
|
||||
virtual void ProcessTurn(ExtractionTurn &turn) = 0;
|
||||
virtual void ProcessSegment(ExtractionSegment &segment) = 0;
|
||||
|
||||
virtual void
|
||||
ProcessElements(const osmium::memory::Buffer &buffer,
|
||||
const RestrictionParser &restriction_parser,
|
||||
std::vector<std::pair<const osmium::Node &, ExtractionNode>> &resulting_nodes,
|
||||
std::vector<std::pair<const osmium::Way &, ExtractionWay>> &resulting_ways,
|
||||
std::vector<InputConditionalTurnRestriction> &resulting_restrictions) = 0;
|
||||
virtual void ProcessElements(
|
||||
const osmium::memory::Buffer &buffer,
|
||||
const RestrictionParser &restriction_parser,
|
||||
const ExtractionRelationContainer &relations,
|
||||
std::vector<std::pair<const osmium::Node &, ExtractionNode>> &resulting_nodes,
|
||||
std::vector<std::pair<const osmium::Way &, ExtractionWay>> &resulting_ways,
|
||||
std::vector<std::pair<const osmium::Relation &, ExtractionRelation>> &resulting_relations,
|
||||
std::vector<InputConditionalTurnRestriction> &resulting_restrictions) = 0;
|
||||
};
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,6 +1,7 @@
|
||||
#ifndef SCRIPTING_ENVIRONMENT_LUA_HPP
|
||||
#define SCRIPTING_ENVIRONMENT_LUA_HPP
|
||||
|
||||
#include "extractor/extraction_relation.hpp"
|
||||
#include "extractor/raster_source.hpp"
|
||||
#include "extractor/scripting_environment.hpp"
|
||||
|
||||
@@ -19,8 +20,13 @@ namespace extractor
|
||||
|
||||
struct LuaScriptingContext final
|
||||
{
|
||||
void ProcessNode(const osmium::Node &, ExtractionNode &result);
|
||||
void ProcessWay(const osmium::Way &, ExtractionWay &result);
|
||||
void ProcessNode(const osmium::Node &,
|
||||
ExtractionNode &result,
|
||||
const ExtractionRelationContainer::RelationList &relations);
|
||||
void ProcessWay(const osmium::Way &,
|
||||
ExtractionWay &result,
|
||||
const ExtractionRelationContainer::RelationList &relations);
|
||||
void ProcessRelation(const osmium::Relation &, ExtractionRelation &result);
|
||||
|
||||
ProfileProperties properties;
|
||||
RasterContainer raster_sources;
|
||||
@@ -29,11 +35,13 @@ struct LuaScriptingContext final
|
||||
bool has_turn_penalty_function;
|
||||
bool has_node_function;
|
||||
bool has_way_function;
|
||||
bool has_relation_function;
|
||||
bool has_segment_function;
|
||||
|
||||
sol::function turn_function;
|
||||
sol::function way_function;
|
||||
sol::function node_function;
|
||||
sol::function relation_function;
|
||||
sol::function segment_function;
|
||||
|
||||
int api_version;
|
||||
@@ -51,7 +59,7 @@ class Sol2ScriptingEnvironment final : public ScriptingEnvironment
|
||||
{
|
||||
public:
|
||||
static const constexpr int SUPPORTED_MIN_API_VERSION = 0;
|
||||
static const constexpr int SUPPORTED_MAX_API_VERSION = 2;
|
||||
static const constexpr int SUPPORTED_MAX_API_VERSION = 3;
|
||||
|
||||
explicit Sol2ScriptingEnvironment(const std::string &file_name);
|
||||
~Sol2ScriptingEnvironment() override = default;
|
||||
@@ -65,12 +73,14 @@ class Sol2ScriptingEnvironment final : public ScriptingEnvironment
|
||||
void ProcessTurn(ExtractionTurn &turn) override;
|
||||
void ProcessSegment(ExtractionSegment &segment) override;
|
||||
|
||||
void
|
||||
ProcessElements(const osmium::memory::Buffer &buffer,
|
||||
const RestrictionParser &restriction_parser,
|
||||
std::vector<std::pair<const osmium::Node &, ExtractionNode>> &resulting_nodes,
|
||||
std::vector<std::pair<const osmium::Way &, ExtractionWay>> &resulting_ways,
|
||||
std::vector<InputConditionalTurnRestriction> &resulting_restrictions) override;
|
||||
void ProcessElements(
|
||||
const osmium::memory::Buffer &buffer,
|
||||
const RestrictionParser &restriction_parser,
|
||||
const ExtractionRelationContainer &relations,
|
||||
std::vector<std::pair<const osmium::Node &, ExtractionNode>> &resulting_nodes,
|
||||
std::vector<std::pair<const osmium::Way &, ExtractionWay>> &resulting_ways,
|
||||
std::vector<std::pair<const osmium::Relation &, ExtractionRelation>> &resulting_relations,
|
||||
std::vector<InputConditionalTurnRestriction> &resulting_restrictions) override;
|
||||
|
||||
private:
|
||||
LuaScriptingContext &GetSol2Context();
|
||||
|
||||
@@ -186,6 +186,7 @@ inline engine_config_ptr argumentsToEngineConfig(const Nan::FunctionCallbackInfo
|
||||
params->Get(Nan::New("max_locations_map_matching").ToLocalChecked());
|
||||
auto max_results_nearest = params->Get(Nan::New("max_results_nearest").ToLocalChecked());
|
||||
auto max_alternatives = params->Get(Nan::New("max_alternatives").ToLocalChecked());
|
||||
auto use_threads_number = params->Get(Nan::New("use_threads_number").ToLocalChecked());
|
||||
|
||||
if (!max_locations_trip->IsUndefined() && !max_locations_trip->IsNumber())
|
||||
{
|
||||
@@ -217,6 +218,11 @@ inline engine_config_ptr argumentsToEngineConfig(const Nan::FunctionCallbackInfo
|
||||
Nan::ThrowError("max_alternatives must be an integral number");
|
||||
return engine_config_ptr();
|
||||
}
|
||||
if (!use_threads_number->IsUndefined() && !use_threads_number->IsNumber())
|
||||
{
|
||||
Nan::ThrowError("use_threads_number must be an integral number");
|
||||
return engine_config_ptr();
|
||||
}
|
||||
|
||||
if (max_locations_trip->IsNumber())
|
||||
engine_config->max_locations_trip = static_cast<int>(max_locations_trip->NumberValue());
|
||||
@@ -233,6 +239,8 @@ inline engine_config_ptr argumentsToEngineConfig(const Nan::FunctionCallbackInfo
|
||||
engine_config->max_results_nearest = static_cast<int>(max_results_nearest->NumberValue());
|
||||
if (max_alternatives->IsNumber())
|
||||
engine_config->max_alternatives = static_cast<int>(max_alternatives->NumberValue());
|
||||
if (use_threads_number->IsNumber())
|
||||
engine_config->use_threads_number = static_cast<int>(use_threads_number->NumberValue());
|
||||
|
||||
return engine_config;
|
||||
}
|
||||
|
||||
+32
-2
@@ -53,10 +53,40 @@ class Log
|
||||
virtual ~Log();
|
||||
std::mutex &get_mutex();
|
||||
|
||||
template <typename T> inline std::ostream &operator<<(const T &data) { return stream << data; }
|
||||
template <typename T> inline Log &operator<<(const T &data)
|
||||
{
|
||||
const auto &policy = LogPolicy::GetInstance();
|
||||
if (!policy.IsMute() && level <= policy.GetLevel())
|
||||
{
|
||||
stream << data;
|
||||
}
|
||||
return *this;
|
||||
}
|
||||
|
||||
template <typename T> inline Log &operator<<(const std::atomic<T> &data)
|
||||
{
|
||||
const auto &policy = LogPolicy::GetInstance();
|
||||
if (!policy.IsMute() && level <= policy.GetLevel())
|
||||
{
|
||||
stream << T(data);
|
||||
}
|
||||
return *this;
|
||||
}
|
||||
|
||||
typedef std::ostream &(manip)(std::ostream &);
|
||||
|
||||
inline Log &operator<<(manip &m)
|
||||
{
|
||||
const auto &policy = LogPolicy::GetInstance();
|
||||
if (!policy.IsMute() && level <= policy.GetLevel())
|
||||
{
|
||||
stream << m;
|
||||
}
|
||||
return *this;
|
||||
}
|
||||
|
||||
protected:
|
||||
LogLevel level;
|
||||
const LogLevel level;
|
||||
std::ostringstream buffer;
|
||||
std::ostream &stream;
|
||||
};
|
||||
|
||||
@@ -83,7 +83,7 @@ class Percent
|
||||
// When not on a TTY, print newlines after each progress indicator so
|
||||
// so that progress is visible to line-buffered logging systems
|
||||
if (!IsStdoutATTY())
|
||||
log << "" << std::endl;
|
||||
log << std::endl;
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
+1
-1
@@ -1,6 +1,6 @@
|
||||
{
|
||||
"name": "osrm",
|
||||
"version": "5.12.0-roundaboutexits.1",
|
||||
"version": "5.13.0-glibc.2",
|
||||
"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": {
|
||||
|
||||
@@ -536,7 +536,7 @@ function process_way(profile, way, result)
|
||||
|
||||
-- handle turn lanes and road classification, used for guidance
|
||||
WayHandlers.classification,
|
||||
|
||||
|
||||
-- handle allowed start/end modes
|
||||
WayHandlers.startpoint,
|
||||
|
||||
@@ -544,7 +544,10 @@ function process_way(profile, way, result)
|
||||
WayHandlers.roundabouts,
|
||||
|
||||
-- set name, ref and pronunciation
|
||||
WayHandlers.names
|
||||
WayHandlers.names,
|
||||
|
||||
-- set weight properties of the way
|
||||
WayHandlers.weights
|
||||
}
|
||||
|
||||
WayHandlers.run(profile,way,result,data,handlers)
|
||||
|
||||
@@ -250,10 +250,12 @@ function setup()
|
||||
|
||||
-- List only exceptions
|
||||
maxspeed_table = {
|
||||
["be:motorway"] = 120,
|
||||
["ch:rural"] = 80,
|
||||
["ch:trunk"] = 100,
|
||||
["ch:motorway"] = 120,
|
||||
["de:living_street"] = 7,
|
||||
["dk:rural"] = 80,
|
||||
["ru:living_street"] = 20,
|
||||
["ru:urban"] = 60,
|
||||
["ua:urban"] = 60,
|
||||
|
||||
+4
-1
@@ -237,7 +237,10 @@ function process_way(profile, way, result)
|
||||
WayHandlers.startpoint,
|
||||
|
||||
-- set name, ref and pronunciation
|
||||
WayHandlers.names
|
||||
WayHandlers.names,
|
||||
|
||||
-- set weight properties of the way
|
||||
WayHandlers.weights
|
||||
}
|
||||
|
||||
WayHandlers.run(profile,way,result,data,handlers)
|
||||
|
||||
@@ -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
|
||||
@@ -20,7 +20,7 @@ bool EngineConfig::IsValid() const
|
||||
unlimited_or_more_than(max_locations_trip, 2) &&
|
||||
unlimited_or_more_than(max_locations_viaroute, 2) &&
|
||||
unlimited_or_more_than(max_results_nearest, 0) &&
|
||||
max_alternatives >= 0;
|
||||
max_alternatives >= 0 && use_threads_number >= 1;
|
||||
|
||||
return ((use_shared_memory && all_path_are_empty) || storage_config.IsValid()) && limits_valid;
|
||||
}
|
||||
|
||||
@@ -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
|
||||
@@ -2,6 +2,7 @@
|
||||
#include "engine/routing_algorithms/routing_base_ch.hpp"
|
||||
|
||||
#include <boost/assert.hpp>
|
||||
#include <boost/range/iterator_range_core.hpp>
|
||||
|
||||
#include <limits>
|
||||
#include <memory>
|
||||
@@ -19,17 +20,33 @@ namespace
|
||||
{
|
||||
struct NodeBucket
|
||||
{
|
||||
unsigned target_id; // essentially a row in the weight matrix
|
||||
NodeID middle_node;
|
||||
unsigned column_index; // a column in the weight/duration matrix
|
||||
EdgeWeight weight;
|
||||
EdgeWeight duration;
|
||||
NodeBucket(const unsigned target_id, const EdgeWeight weight, const EdgeWeight duration)
|
||||
: target_id(target_id), weight(weight), duration(duration)
|
||||
EdgeDuration duration;
|
||||
|
||||
NodeBucket(NodeID middle_node, unsigned column_index, EdgeWeight weight, EdgeDuration duration)
|
||||
: middle_node(middle_node), column_index(column_index), weight(weight), duration(duration)
|
||||
{
|
||||
}
|
||||
};
|
||||
|
||||
// FIXME This should be replaced by an std::unordered_multimap, though this needs benchmarking
|
||||
using SearchSpaceWithBuckets = std::unordered_map<NodeID, std::vector<NodeBucket>>;
|
||||
// partial order comparison
|
||||
bool operator<(const NodeBucket &rhs) const { return middle_node < rhs.middle_node; }
|
||||
|
||||
// functor for equal_range
|
||||
struct Compare
|
||||
{
|
||||
bool operator()(const NodeBucket &lhs, const NodeID &rhs) const
|
||||
{
|
||||
return lhs.middle_node < rhs;
|
||||
}
|
||||
|
||||
bool operator()(const NodeID &lhs, const NodeBucket &rhs) const
|
||||
{
|
||||
return lhs < rhs.middle_node;
|
||||
}
|
||||
};
|
||||
};
|
||||
|
||||
inline bool addLoopWeight(const DataFacade<ch::Algorithm> &facade,
|
||||
const NodeID node,
|
||||
@@ -74,12 +91,12 @@ void relaxOutgoingEdges(const DataFacade<ch::Algorithm> &facade,
|
||||
{
|
||||
const NodeID to = facade.GetTarget(edge);
|
||||
|
||||
const EdgeWeight edge_weight = data.weight;
|
||||
const EdgeWeight edge_duration = data.duration;
|
||||
const auto edge_weight = data.weight;
|
||||
const auto edge_duration = data.duration;
|
||||
|
||||
BOOST_ASSERT_MSG(edge_weight > 0, "edge_weight invalid");
|
||||
const EdgeWeight to_weight = weight + edge_weight;
|
||||
const EdgeWeight to_duration = duration + edge_duration;
|
||||
const auto to_weight = weight + edge_weight;
|
||||
const auto to_duration = duration + edge_duration;
|
||||
|
||||
// New Node discovered -> Add to Heap + Node Info Storage
|
||||
if (!query_heap.WasInserted(to))
|
||||
@@ -87,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};
|
||||
@@ -103,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));
|
||||
|
||||
@@ -117,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);
|
||||
|
||||
@@ -148,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);
|
||||
@@ -177,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);
|
||||
@@ -201,12 +262,12 @@ void relaxOutgoingEdges(const DataFacade<mld::Algorithm> &facade,
|
||||
continue;
|
||||
}
|
||||
|
||||
const EdgeWeight edge_weight = data.weight;
|
||||
const EdgeWeight edge_duration = data.duration;
|
||||
const auto edge_weight = data.weight;
|
||||
const auto edge_duration = data.duration;
|
||||
|
||||
BOOST_ASSERT_MSG(edge_weight > 0, "edge_weight invalid");
|
||||
const EdgeWeight to_weight = weight + edge_weight;
|
||||
const EdgeWeight to_duration = duration + edge_duration;
|
||||
const auto to_weight = weight + edge_weight;
|
||||
const auto to_duration = duration + edge_duration;
|
||||
|
||||
// New Node discovered -> Add to Heap + Node Info Storage
|
||||
if (!query_heap.WasInserted(to))
|
||||
@@ -214,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};
|
||||
@@ -229,49 +291,47 @@ void forwardRoutingStep(const DataFacade<Algorithm> &facade,
|
||||
const unsigned row_idx,
|
||||
const unsigned number_of_targets,
|
||||
typename SearchEngineData<Algorithm>::ManyToManyQueryHeap &query_heap,
|
||||
const SearchSpaceWithBuckets &search_space_with_buckets,
|
||||
const std::vector<NodeBucket> &search_space_with_buckets,
|
||||
std::vector<EdgeWeight> &weights_table,
|
||||
std::vector<EdgeWeight> &durations_table,
|
||||
std::vector<EdgeDuration> &durations_table,
|
||||
const PhantomNode &phantom_node)
|
||||
{
|
||||
const NodeID node = query_heap.DeleteMin();
|
||||
const EdgeWeight source_weight = query_heap.GetKey(node);
|
||||
const EdgeWeight source_duration = query_heap.GetData(node).duration;
|
||||
const auto node = query_heap.DeleteMin();
|
||||
const auto source_weight = query_heap.GetKey(node);
|
||||
const auto source_duration = query_heap.GetData(node).duration;
|
||||
|
||||
// check if each encountered node has an entry
|
||||
const auto bucket_iterator = search_space_with_buckets.find(node);
|
||||
// iterate bucket if there exists one
|
||||
if (bucket_iterator != search_space_with_buckets.end())
|
||||
const auto &bucket_list = std::equal_range(search_space_with_buckets.begin(),
|
||||
search_space_with_buckets.end(),
|
||||
node,
|
||||
NodeBucket::Compare());
|
||||
for (const auto ¤t_bucket : boost::make_iterator_range(bucket_list))
|
||||
{
|
||||
const std::vector<NodeBucket> &bucket_list = bucket_iterator->second;
|
||||
for (const NodeBucket ¤t_bucket : bucket_list)
|
||||
// get target id from bucket entry
|
||||
const auto column_idx = current_bucket.column_index;
|
||||
const auto target_weight = current_bucket.weight;
|
||||
const auto target_duration = current_bucket.duration;
|
||||
|
||||
auto ¤t_weight = weights_table[row_idx * number_of_targets + column_idx];
|
||||
auto ¤t_duration = durations_table[row_idx * number_of_targets + column_idx];
|
||||
|
||||
// check if new weight is better
|
||||
auto new_weight = source_weight + target_weight;
|
||||
auto new_duration = source_duration + target_duration;
|
||||
|
||||
if (new_weight < 0)
|
||||
{
|
||||
// get target id from bucket entry
|
||||
const unsigned column_idx = current_bucket.target_id;
|
||||
const EdgeWeight target_weight = current_bucket.weight;
|
||||
const EdgeWeight target_duration = current_bucket.duration;
|
||||
|
||||
auto ¤t_weight = weights_table[row_idx * number_of_targets + column_idx];
|
||||
auto ¤t_duration = durations_table[row_idx * number_of_targets + column_idx];
|
||||
|
||||
// check if new weight is better
|
||||
auto new_weight = source_weight + target_weight;
|
||||
auto new_duration = source_duration + target_duration;
|
||||
|
||||
if (new_weight < 0)
|
||||
if (addLoopWeight(facade, node, new_weight, new_duration))
|
||||
{
|
||||
if (addLoopWeight(facade, node, new_weight, new_duration))
|
||||
{
|
||||
current_weight = std::min(current_weight, new_weight);
|
||||
current_duration = std::min(current_duration, new_duration);
|
||||
}
|
||||
}
|
||||
else if (new_weight < current_weight)
|
||||
{
|
||||
current_weight = new_weight;
|
||||
current_duration = new_duration;
|
||||
current_weight = std::min(current_weight, new_weight);
|
||||
current_duration = std::min(current_duration, new_duration);
|
||||
}
|
||||
}
|
||||
else if (std::tie(new_weight, new_duration) < std::tie(current_weight, current_duration))
|
||||
{
|
||||
current_weight = new_weight;
|
||||
current_duration = new_duration;
|
||||
}
|
||||
}
|
||||
|
||||
relaxOutgoingEdges<FORWARD_DIRECTION>(
|
||||
@@ -282,15 +342,15 @@ template <typename Algorithm>
|
||||
void backwardRoutingStep(const DataFacade<Algorithm> &facade,
|
||||
const unsigned column_idx,
|
||||
typename SearchEngineData<Algorithm>::ManyToManyQueryHeap &query_heap,
|
||||
SearchSpaceWithBuckets &search_space_with_buckets,
|
||||
std::vector<NodeBucket> &search_space_with_buckets,
|
||||
const PhantomNode &phantom_node)
|
||||
{
|
||||
const NodeID node = query_heap.DeleteMin();
|
||||
const EdgeWeight target_weight = query_heap.GetKey(node);
|
||||
const EdgeWeight target_duration = query_heap.GetData(node).duration;
|
||||
const auto node = query_heap.DeleteMin();
|
||||
const auto target_weight = query_heap.GetKey(node);
|
||||
const auto target_duration = query_heap.GetData(node).duration;
|
||||
|
||||
// store settled nodes in search space bucket
|
||||
search_space_with_buckets[node].emplace_back(column_idx, target_weight, target_duration);
|
||||
search_space_with_buckets.emplace_back(node, column_idx, target_weight, target_duration);
|
||||
|
||||
relaxOutgoingEdges<REVERSE_DIRECTION>(
|
||||
facade, node, target_weight, target_duration, query_heap, phantom_node);
|
||||
@@ -298,111 +358,297 @@ 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,
|
||||
const std::vector<std::size_t> &source_indices,
|
||||
const 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)
|
||||
{
|
||||
const auto number_of_sources =
|
||||
source_indices.empty() ? phantom_nodes.size() : source_indices.size();
|
||||
const auto number_of_targets =
|
||||
target_indices.empty() ? phantom_nodes.size() : target_indices.size();
|
||||
if (source_indices.empty())
|
||||
{
|
||||
source_indices.resize(phantom_nodes.size());
|
||||
std::iota(source_indices.begin(), source_indices.end(), 0);
|
||||
}
|
||||
if (target_indices.empty())
|
||||
{
|
||||
target_indices.resize(phantom_nodes.size());
|
||||
std::iota(target_indices.begin(), target_indices.end(), 0);
|
||||
}
|
||||
|
||||
const auto number_of_sources = source_indices.size();
|
||||
const auto number_of_targets = target_indices.size();
|
||||
const auto number_of_entries = number_of_sources * number_of_targets;
|
||||
|
||||
std::vector<EdgeWeight> weights_table(number_of_entries, INVALID_EDGE_WEIGHT);
|
||||
std::vector<EdgeWeight> durations_table(number_of_entries, MAXIMAL_EDGE_DURATION);
|
||||
std::vector<EdgeDuration> durations_table(number_of_entries, MAXIMAL_EDGE_DURATION);
|
||||
|
||||
engine_working_data.InitializeOrClearManyToManyThreadLocalStorage(facade.GetNumberOfNodes());
|
||||
std::mutex lock;
|
||||
std::vector<NodeBucket> search_space_with_buckets;
|
||||
|
||||
auto &query_heap = *(engine_working_data.many_to_many_heap);
|
||||
// Backward search for target phantoms
|
||||
tbb::parallel_for(
|
||||
tbb::blocked_range<std::size_t>{0, target_indices.size()},
|
||||
[&](const tbb::blocked_range<std::size_t> &chunk) {
|
||||
for (auto column_idx = chunk.begin(), end = chunk.end(); column_idx != end;
|
||||
++column_idx)
|
||||
{
|
||||
const auto index = target_indices[column_idx];
|
||||
const auto &phantom = phantom_nodes[index];
|
||||
|
||||
SearchSpaceWithBuckets search_space_with_buckets;
|
||||
engine_working_data.InitializeOrClearManyToManyThreadLocalStorage(
|
||||
facade.GetNumberOfNodes());
|
||||
auto &query_heap = *(engine_working_data.many_to_many_heap);
|
||||
insertTargetInHeap(query_heap, phantom);
|
||||
|
||||
unsigned column_idx = 0;
|
||||
const auto search_target_phantom = [&](const PhantomNode &phantom) {
|
||||
// clear heap and insert target nodes
|
||||
query_heap.Clear();
|
||||
insertTargetInHeap(query_heap, phantom);
|
||||
// explore search space
|
||||
std::vector<NodeBucket> local_buckets;
|
||||
while (!query_heap.Empty())
|
||||
{
|
||||
backwardRoutingStep(facade, column_idx, query_heap, local_buckets, phantom);
|
||||
}
|
||||
|
||||
// explore search space
|
||||
while (!query_heap.Empty())
|
||||
{
|
||||
backwardRoutingStep(facade, column_idx, query_heap, search_space_with_buckets, phantom);
|
||||
}
|
||||
++column_idx;
|
||||
};
|
||||
{ // Insert local buckets into the global search space
|
||||
std::lock_guard<std::mutex> guard{lock};
|
||||
search_space_with_buckets.insert(std::end(search_space_with_buckets),
|
||||
std::begin(local_buckets),
|
||||
std::end(local_buckets));
|
||||
}
|
||||
}
|
||||
});
|
||||
|
||||
// for each source do forward search
|
||||
unsigned row_idx = 0;
|
||||
const auto search_source_phantom = [&](const PhantomNode &phantom) {
|
||||
// clear heap and insert source nodes
|
||||
query_heap.Clear();
|
||||
insertSourceInHeap(query_heap, phantom);
|
||||
tbb::parallel_sort(search_space_with_buckets.begin(), search_space_with_buckets.end());
|
||||
|
||||
// explore search space
|
||||
while (!query_heap.Empty())
|
||||
{
|
||||
forwardRoutingStep(facade,
|
||||
row_idx,
|
||||
number_of_targets,
|
||||
query_heap,
|
||||
search_space_with_buckets,
|
||||
weights_table,
|
||||
durations_table,
|
||||
phantom);
|
||||
}
|
||||
++row_idx;
|
||||
};
|
||||
// For each source do forward search
|
||||
tbb::parallel_for(tbb::blocked_range<std::size_t>{0, source_indices.size()},
|
||||
[&](const tbb::blocked_range<std::size_t> &chunk) {
|
||||
for (auto row_idx = chunk.begin(), end = chunk.end(); row_idx != end;
|
||||
++row_idx)
|
||||
{
|
||||
const auto index = source_indices[row_idx];
|
||||
const auto &phantom = phantom_nodes[index];
|
||||
|
||||
if (target_indices.empty())
|
||||
{
|
||||
for (const auto &phantom : phantom_nodes)
|
||||
{
|
||||
search_target_phantom(phantom);
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
for (const auto index : target_indices)
|
||||
{
|
||||
const auto &phantom = phantom_nodes[index];
|
||||
search_target_phantom(phantom);
|
||||
}
|
||||
}
|
||||
// clear heap and insert source nodes
|
||||
engine_working_data.InitializeOrClearManyToManyThreadLocalStorage(
|
||||
facade.GetNumberOfNodes());
|
||||
auto &query_heap = *(engine_working_data.many_to_many_heap);
|
||||
insertSourceInHeap(query_heap, phantom);
|
||||
|
||||
if (source_indices.empty())
|
||||
{
|
||||
for (const auto &phantom : phantom_nodes)
|
||||
{
|
||||
search_source_phantom(phantom);
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
for (const auto index : source_indices)
|
||||
{
|
||||
const auto &phantom = phantom_nodes[index];
|
||||
search_source_phantom(phantom);
|
||||
}
|
||||
}
|
||||
// explore search space
|
||||
while (!query_heap.Empty())
|
||||
{
|
||||
forwardRoutingStep(facade,
|
||||
row_idx,
|
||||
number_of_targets,
|
||||
query_heap,
|
||||
search_space_with_buckets,
|
||||
weights_table,
|
||||
durations_table,
|
||||
phantom);
|
||||
}
|
||||
}
|
||||
});
|
||||
|
||||
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,
|
||||
const std::vector<std::size_t> &source_indices,
|
||||
const std::vector<std::size_t> &target_indices);
|
||||
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,
|
||||
const std::vector<std::size_t> &source_indices,
|
||||
const std::vector<std::size_t> &target_indices);
|
||||
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
|
||||
|
||||
@@ -3,6 +3,7 @@
|
||||
#include "extractor/edge_based_edge.hpp"
|
||||
#include "extractor/extraction_containers.hpp"
|
||||
#include "extractor/extraction_node.hpp"
|
||||
#include "extractor/extraction_relation.hpp"
|
||||
#include "extractor/extraction_way.hpp"
|
||||
#include "extractor/extractor_callbacks.hpp"
|
||||
#include "extractor/files.hpp"
|
||||
@@ -288,12 +289,13 @@ Extractor::ParseOSMData(ScriptingEnvironment &scripting_environment,
|
||||
|
||||
const osmium::io::File input_file(config.input_path.string());
|
||||
osmium::thread::Pool pool(number_of_threads);
|
||||
osmium::io::Reader reader(
|
||||
input_file,
|
||||
pool,
|
||||
(config.use_metadata ? osmium::io::read_meta::yes : osmium::io::read_meta::no));
|
||||
|
||||
const osmium::io::Header header = reader.header();
|
||||
std::unique_ptr<osmium::io::Reader> reader(new osmium::io::Reader(
|
||||
input_file,
|
||||
osmium::osm_entity_bits::relation,
|
||||
(config.use_metadata ? osmium::io::read_meta::yes : osmium::io::read_meta::no)));
|
||||
|
||||
osmium::io::Header header = reader->header();
|
||||
|
||||
unsigned number_of_nodes = 0;
|
||||
unsigned number_of_ways = 0;
|
||||
@@ -331,6 +333,7 @@ Extractor::ParseOSMData(ScriptingEnvironment &scripting_environment,
|
||||
|
||||
timestamp_file.WriteFrom(timestamp.c_str(), timestamp.length());
|
||||
|
||||
ExtractionRelationContainer relations;
|
||||
std::vector<std::string> restrictions = scripting_environment.GetRestrictions();
|
||||
// setup restriction parser
|
||||
const RestrictionParser restriction_parser(
|
||||
@@ -338,20 +341,19 @@ Extractor::ParseOSMData(ScriptingEnvironment &scripting_environment,
|
||||
config.parse_conditionals,
|
||||
restrictions);
|
||||
|
||||
std::mutex process_mutex;
|
||||
|
||||
using SharedBuffer = std::shared_ptr<const osmium::memory::Buffer>;
|
||||
struct ParsedBuffer
|
||||
{
|
||||
SharedBuffer buffer;
|
||||
std::vector<std::pair<const osmium::Node &, ExtractionNode>> resulting_nodes;
|
||||
std::vector<std::pair<const osmium::Way &, ExtractionWay>> resulting_ways;
|
||||
std::vector<std::pair<const osmium::Relation &, ExtractionRelation>> resulting_relations;
|
||||
std::vector<InputConditionalTurnRestriction> resulting_restrictions;
|
||||
};
|
||||
|
||||
tbb::filter_t<void, SharedBuffer> buffer_reader(
|
||||
tbb::filter::serial_in_order, [&](tbb::flow_control &fc) {
|
||||
if (auto buffer = reader.read())
|
||||
if (auto buffer = reader->read())
|
||||
{
|
||||
return std::make_shared<const osmium::memory::Buffer>(std::move(buffer));
|
||||
}
|
||||
@@ -370,8 +372,10 @@ Extractor::ParseOSMData(ScriptingEnvironment &scripting_environment,
|
||||
parsed_buffer->buffer = buffer;
|
||||
scripting_environment.ProcessElements(*buffer,
|
||||
restriction_parser,
|
||||
relations,
|
||||
parsed_buffer->resulting_nodes,
|
||||
parsed_buffer->resulting_ways,
|
||||
parsed_buffer->resulting_relations,
|
||||
parsed_buffer->resulting_restrictions);
|
||||
return parsed_buffer;
|
||||
});
|
||||
@@ -391,13 +395,46 @@ Extractor::ParseOSMData(ScriptingEnvironment &scripting_environment,
|
||||
{
|
||||
extractor_callbacks->ProcessWay(result.first, result.second);
|
||||
}
|
||||
number_of_relations += parsed_buffer->resulting_restrictions.size();
|
||||
});
|
||||
|
||||
tbb::filter_t<std::shared_ptr<ParsedBuffer>, void> buffer_storage_relation(
|
||||
tbb::filter::serial_in_order, [&](const std::shared_ptr<ParsedBuffer> parsed_buffer) {
|
||||
if (!parsed_buffer)
|
||||
return;
|
||||
|
||||
number_of_relations += parsed_buffer->resulting_relations.size();
|
||||
for (const auto &result : parsed_buffer->resulting_relations)
|
||||
{
|
||||
/// TODO: add restriction processing
|
||||
if (result.second.is_restriction)
|
||||
continue;
|
||||
|
||||
relations.AddRelation(result.second);
|
||||
}
|
||||
|
||||
for (const auto &result : parsed_buffer->resulting_restrictions)
|
||||
{
|
||||
extractor_callbacks->ProcessRestriction(result);
|
||||
}
|
||||
});
|
||||
|
||||
/* Main trick that we can use the same pipeline. It just receive relation objects
|
||||
* from osmium. So other containers would be empty and doesn't process anything
|
||||
*/
|
||||
util::Log() << "Parse relations ...";
|
||||
tbb::parallel_pipeline(tbb::task_scheduler_init::default_num_threads() * 1.5,
|
||||
buffer_reader & buffer_transform & buffer_storage_relation);
|
||||
reader->close();
|
||||
|
||||
/* At this step we just filter ways and nodes from osmium, so any relation wouldn't be
|
||||
* processed there.
|
||||
*/
|
||||
util::Log() << "Parse ways and nodes ...";
|
||||
reader.reset(new osmium::io::Reader(
|
||||
input_file,
|
||||
osmium::osm_entity_bits::node | osmium::osm_entity_bits::way,
|
||||
(config.use_metadata ? osmium::io::read_meta::yes : osmium::io::read_meta::no)));
|
||||
|
||||
// Number of pipeline tokens that yielded the best speedup was about 1.5 * num_cores
|
||||
tbb::parallel_pipeline(tbb::task_scheduler_init::default_num_threads() * 1.5,
|
||||
buffer_reader & buffer_transform & buffer_storage);
|
||||
|
||||
@@ -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,
|
||||
|
||||
@@ -54,12 +54,19 @@ IntersectionGenerator::ComputeIntersectionShape(const NodeID node_at_center_of_i
|
||||
const boost::optional<NodeID> sorting_base,
|
||||
const bool use_low_precision_angles) const
|
||||
{
|
||||
IntersectionShape intersection;
|
||||
// reserve enough items (+ the possibly missing u-turn edge)
|
||||
const auto intersection_degree = node_based_graph.GetOutDegree(node_at_center_of_intersection);
|
||||
intersection.reserve(intersection_degree);
|
||||
const util::Coordinate turn_coordinate = coordinates[node_at_center_of_intersection];
|
||||
|
||||
// compute bearings in a relatively small circle to prevent wrong roads order with true bearings
|
||||
struct RoadWithInitialBearing
|
||||
{
|
||||
double bearing;
|
||||
IntersectionShapeData road;
|
||||
};
|
||||
std::vector<RoadWithInitialBearing> initial_roads_ordering;
|
||||
// reserve enough items (+ the possibly missing u-turn edge)
|
||||
initial_roads_ordering.reserve(intersection_degree);
|
||||
|
||||
// number of lanes at the intersection changes how far we look down the road
|
||||
const auto edge_range = node_based_graph.GetAdjacentEdgeRange(node_at_center_of_intersection);
|
||||
const auto max_lanes_intersection = std::accumulate(
|
||||
@@ -82,6 +89,11 @@ IntersectionGenerator::ComputeIntersectionShape(const NodeID node_at_center_of_i
|
||||
auto coordinates = coordinate_extractor.GetCoordinatesAlongRoad(
|
||||
node_at_center_of_intersection, edge_connected_to_intersection, !INVERT, to_node);
|
||||
|
||||
const auto close_coordinate =
|
||||
coordinate_extractor.ExtractCoordinateAtLength(2. /*m*/, coordinates);
|
||||
const auto initial_bearing =
|
||||
util::coordinate_calculation::bearing(turn_coordinate, close_coordinate);
|
||||
|
||||
const auto segment_length = util::coordinate_calculation::getLength(
|
||||
coordinates.begin(),
|
||||
coordinates.end(),
|
||||
@@ -123,31 +135,79 @@ IntersectionGenerator::ComputeIntersectionShape(const NodeID node_at_center_of_i
|
||||
BOOST_ASSERT(std::abs(bearing) <= 0.1);
|
||||
}
|
||||
|
||||
intersection.push_back({edge_connected_to_intersection, bearing, segment_length});
|
||||
initial_roads_ordering.push_back(
|
||||
{initial_bearing, {edge_connected_to_intersection, bearing, segment_length}});
|
||||
}
|
||||
|
||||
if (!intersection.empty())
|
||||
if (!initial_roads_ordering.empty())
|
||||
{
|
||||
const auto base_bearing = [&]() {
|
||||
const auto base_initial_bearing = [&]() {
|
||||
if (sorting_base)
|
||||
{
|
||||
const auto itr =
|
||||
std::find_if(intersection.begin(),
|
||||
intersection.end(),
|
||||
[&](const IntersectionShapeData &data) {
|
||||
return node_based_graph.GetTarget(data.eid) == *sorting_base;
|
||||
});
|
||||
if (itr != intersection.end())
|
||||
const auto itr = std::find_if(initial_roads_ordering.begin(),
|
||||
initial_roads_ordering.end(),
|
||||
[&](const auto &data) {
|
||||
return node_based_graph.GetTarget(
|
||||
data.road.eid) == *sorting_base;
|
||||
});
|
||||
if (itr != initial_roads_ordering.end())
|
||||
return util::bearing::reverse(itr->bearing);
|
||||
}
|
||||
return util::bearing::reverse(intersection.begin()->bearing);
|
||||
return util::bearing::reverse(initial_roads_ordering.begin()->bearing);
|
||||
}();
|
||||
std::sort(intersection.begin(),
|
||||
intersection.end(),
|
||||
makeCompareShapeDataAngleToBearing(base_bearing));
|
||||
|
||||
// sort roads with respect to the initial bearings, a tie-breaker for equal initial bearings
|
||||
// is to order roads via final bearings to have roads in clockwise order
|
||||
//
|
||||
// rhs <---. lhs <----.
|
||||
// / /
|
||||
// lhs / rhs /
|
||||
//
|
||||
// lhs road is before rhs one rhs road is before lhs one
|
||||
// bearing::angleBetween < 180 bearing::angleBetween > 180
|
||||
const auto initial_bearing_order = makeCompareShapeDataAngleToBearing(base_initial_bearing);
|
||||
std::sort(initial_roads_ordering.begin(),
|
||||
initial_roads_ordering.end(),
|
||||
[&initial_bearing_order](const auto &lhs, const auto &rhs) {
|
||||
return initial_bearing_order(lhs, rhs) ||
|
||||
(lhs.bearing == rhs.bearing &&
|
||||
util::bearing::angleBetween(lhs.road.bearing, rhs.road.bearing) <
|
||||
180);
|
||||
});
|
||||
|
||||
// copy intersection data in the initial order
|
||||
IntersectionShape intersection;
|
||||
intersection.reserve(initial_roads_ordering.size());
|
||||
std::transform(initial_roads_ordering.begin(),
|
||||
initial_roads_ordering.end(),
|
||||
std::back_inserter(intersection),
|
||||
[](const auto &entry) { return entry.road; });
|
||||
|
||||
if (intersection.size() > 2)
|
||||
{ // Check bearings ordering with respect to true bearings
|
||||
const auto base_bearing = intersection.front().bearing;
|
||||
const auto bearings_order =
|
||||
makeCompareShapeDataAngleToBearing(util::bearing::reverse(base_bearing));
|
||||
for (auto curr = intersection.begin(), next = std::next(curr);
|
||||
next != intersection.end();
|
||||
++curr, ++next)
|
||||
{
|
||||
if (bearings_order(*next, *curr))
|
||||
{ // If the true bearing is out of the initial order (next before current) then
|
||||
// adjust the next bearing to keep the order. The adjustment angle is at most
|
||||
// 0.5° or a half-angle between the current bearing and the base bearing.
|
||||
// to prevent overlapping over base bearing + 360°.
|
||||
const auto angle_adjustment = std::min(
|
||||
.5, util::restrictAngleToValidRange(base_bearing - curr->bearing) / 2.);
|
||||
next->bearing =
|
||||
util::restrictAngleToValidRange(curr->bearing + angle_adjustment);
|
||||
}
|
||||
}
|
||||
}
|
||||
return intersection;
|
||||
}
|
||||
|
||||
return intersection;
|
||||
return IntersectionShape{};
|
||||
}
|
||||
|
||||
// a
|
||||
|
||||
@@ -2,6 +2,7 @@
|
||||
|
||||
#include "extractor/extraction_helper_functions.hpp"
|
||||
#include "extractor/extraction_node.hpp"
|
||||
#include "extractor/extraction_relation.hpp"
|
||||
#include "extractor/extraction_segment.hpp"
|
||||
#include "extractor/extraction_turn.hpp"
|
||||
#include "extractor/extraction_way.hpp"
|
||||
@@ -31,6 +32,9 @@ template <> struct is_container<osmium::Node> : std::false_type
|
||||
template <> struct is_container<osmium::Way> : std::false_type
|
||||
{
|
||||
};
|
||||
template <> struct is_container<osmium::Relation> : std::false_type
|
||||
{
|
||||
};
|
||||
}
|
||||
|
||||
namespace osrm
|
||||
@@ -216,6 +220,14 @@ void Sol2ScriptingEnvironment::InitContext(LuaScriptingContext &context)
|
||||
"sharp_left",
|
||||
extractor::guidance::DirectionModifier::SharpLeft);
|
||||
|
||||
context.state.new_enum("item_type",
|
||||
"node",
|
||||
osmium::item_type::node,
|
||||
"way",
|
||||
osmium::item_type::way,
|
||||
"relation",
|
||||
osmium::item_type::relation);
|
||||
|
||||
context.state.new_usertype<RasterContainer>("raster",
|
||||
"load",
|
||||
&RasterContainer::LoadRasterSource,
|
||||
@@ -276,6 +288,30 @@ void Sol2ScriptingEnvironment::InitContext(LuaScriptingContext &context)
|
||||
"version",
|
||||
&osmium::Way::version);
|
||||
|
||||
context.state.new_usertype<osmium::RelationMember>(
|
||||
"RelationMember",
|
||||
"role",
|
||||
&osmium::RelationMember::role,
|
||||
"type",
|
||||
&osmium::RelationMember::type,
|
||||
"id",
|
||||
[](const osmium::RelationMember &member) -> osmium::object_id_type {
|
||||
return member.ref();
|
||||
});
|
||||
|
||||
context.state.new_usertype<osmium::Relation>(
|
||||
"Relation",
|
||||
"get_value_by_key",
|
||||
&get_value_by_key<osmium::Relation>,
|
||||
"id",
|
||||
&osmium::Relation::id,
|
||||
"version",
|
||||
&osmium::Relation::version,
|
||||
"members",
|
||||
[](const osmium::Relation &rel) -> const osmium::RelationMemberList & {
|
||||
return rel.members();
|
||||
});
|
||||
|
||||
context.state.new_usertype<osmium::Node>("Node",
|
||||
"location",
|
||||
&osmium::Node::location,
|
||||
@@ -284,7 +320,7 @@ void Sol2ScriptingEnvironment::InitContext(LuaScriptingContext &context)
|
||||
"id",
|
||||
&osmium::Node::id,
|
||||
"version",
|
||||
&osmium::Way::version);
|
||||
&osmium::Node::version);
|
||||
|
||||
context.state.new_usertype<ExtractionNode>("ResultNode",
|
||||
"traffic_lights",
|
||||
@@ -366,6 +402,18 @@ void Sol2ScriptingEnvironment::InitContext(LuaScriptingContext &context)
|
||||
sol::property([](const ExtractionWay &way) { return way.backward_restricted; },
|
||||
[](ExtractionWay &way, bool flag) { way.backward_restricted = flag; }));
|
||||
|
||||
context.state.new_usertype<ExtractionRelation>(
|
||||
"ExtractionRelation",
|
||||
sol::meta_function::new_index,
|
||||
[](ExtractionRelation &rel, const osmium::RelationMember &member)
|
||||
-> ExtractionRelation::AttributesMap & { return rel.GetMember(member); },
|
||||
sol::meta_function::index,
|
||||
[](ExtractionRelation &rel, const osmium::RelationMember &member)
|
||||
-> ExtractionRelation::AttributesMap & { return rel.GetMember(member); },
|
||||
"restriction",
|
||||
sol::property([](const ExtractionRelation &rel) { return rel.is_restriction; },
|
||||
[](ExtractionRelation &rel, bool flag) { rel.is_restriction = flag; }));
|
||||
|
||||
context.state.new_usertype<ExtractionSegment>("ExtractionSegment",
|
||||
"source",
|
||||
&ExtractionSegment::source,
|
||||
@@ -457,10 +505,7 @@ void Sol2ScriptingEnvironment::InitContext(LuaScriptingContext &context)
|
||||
util::Log() << "Using profile api version " << context.api_version;
|
||||
|
||||
// version-dependent parts of the api
|
||||
switch (context.api_version)
|
||||
{
|
||||
case 2:
|
||||
{
|
||||
auto initV2Context = [&]() {
|
||||
// clear global not used in v2
|
||||
context.state["properties"] = sol::nullopt;
|
||||
|
||||
@@ -543,6 +588,22 @@ void Sol2ScriptingEnvironment::InitContext(LuaScriptingContext &context)
|
||||
if (force_split_edges != sol::nullopt)
|
||||
context.properties.force_split_edges = force_split_edges.value();
|
||||
}
|
||||
};
|
||||
|
||||
switch (context.api_version)
|
||||
{
|
||||
case 3:
|
||||
{
|
||||
initV2Context();
|
||||
context.relation_function = function_table.value()["process_relation"];
|
||||
|
||||
context.has_relation_function = context.relation_function.valid();
|
||||
break;
|
||||
}
|
||||
|
||||
case 2:
|
||||
{
|
||||
initV2Context();
|
||||
break;
|
||||
}
|
||||
case 1:
|
||||
@@ -615,12 +676,15 @@ LuaScriptingContext &Sol2ScriptingEnvironment::GetSol2Context()
|
||||
void Sol2ScriptingEnvironment::ProcessElements(
|
||||
const osmium::memory::Buffer &buffer,
|
||||
const RestrictionParser &restriction_parser,
|
||||
const ExtractionRelationContainer &relations,
|
||||
std::vector<std::pair<const osmium::Node &, ExtractionNode>> &resulting_nodes,
|
||||
std::vector<std::pair<const osmium::Way &, ExtractionWay>> &resulting_ways,
|
||||
std::vector<std::pair<const osmium::Relation &, ExtractionRelation>> &resulting_relations,
|
||||
std::vector<InputConditionalTurnRestriction> &resulting_restrictions)
|
||||
{
|
||||
ExtractionNode result_node;
|
||||
ExtractionWay result_way;
|
||||
ExtractionRelation result_relation;
|
||||
auto &local_context = this->GetSol2Context();
|
||||
|
||||
for (auto entity = buffer.cbegin(), end = buffer.cend(); entity != end; ++entity)
|
||||
@@ -628,33 +692,47 @@ void Sol2ScriptingEnvironment::ProcessElements(
|
||||
switch (entity->type())
|
||||
{
|
||||
case osmium::item_type::node:
|
||||
{
|
||||
const auto &node = static_cast<const osmium::Node &>(*entity);
|
||||
result_node.clear();
|
||||
if (local_context.has_node_function &&
|
||||
(!static_cast<const osmium::Node &>(*entity).tags().empty() ||
|
||||
local_context.properties.call_tagless_node_function))
|
||||
(!node.tags().empty() || local_context.properties.call_tagless_node_function))
|
||||
{
|
||||
local_context.ProcessNode(static_cast<const osmium::Node &>(*entity), result_node);
|
||||
const auto &id = ExtractionRelation::OsmIDTyped(node.id(), osmium::item_type::node);
|
||||
local_context.ProcessNode(node, result_node, relations.Get(id));
|
||||
}
|
||||
resulting_nodes.push_back(std::pair<const osmium::Node &, ExtractionNode>(
|
||||
static_cast<const osmium::Node &>(*entity), std::move(result_node)));
|
||||
break;
|
||||
resulting_nodes.push_back({node, std::move(result_node)});
|
||||
}
|
||||
break;
|
||||
case osmium::item_type::way:
|
||||
{
|
||||
const osmium::Way &way = static_cast<const osmium::Way &>(*entity);
|
||||
result_way.clear();
|
||||
if (local_context.has_way_function)
|
||||
{
|
||||
local_context.ProcessWay(static_cast<const osmium::Way &>(*entity), result_way);
|
||||
const auto &id = ExtractionRelation::OsmIDTyped(way.id(), osmium::item_type::way);
|
||||
local_context.ProcessWay(way, result_way, relations.Get(id));
|
||||
}
|
||||
resulting_ways.push_back(std::pair<const osmium::Way &, ExtractionWay>(
|
||||
static_cast<const osmium::Way &>(*entity), std::move(result_way)));
|
||||
break;
|
||||
resulting_ways.push_back({way, std::move(result_way)});
|
||||
}
|
||||
break;
|
||||
case osmium::item_type::relation:
|
||||
{
|
||||
auto result_res =
|
||||
restriction_parser.TryParse(static_cast<const osmium::Relation &>(*entity));
|
||||
if (result_res)
|
||||
const auto &relation = static_cast<const osmium::Relation &>(*entity);
|
||||
if (auto result_res = restriction_parser.TryParse(relation))
|
||||
{
|
||||
resulting_restrictions.push_back(*result_res);
|
||||
}
|
||||
|
||||
if (local_context.api_version > 2)
|
||||
{
|
||||
result_relation.clear();
|
||||
if (local_context.has_relation_function)
|
||||
{
|
||||
local_context.ProcessRelation(relation, result_relation);
|
||||
}
|
||||
resulting_relations.push_back({relation, std::move(result_relation)});
|
||||
}
|
||||
}
|
||||
break;
|
||||
default:
|
||||
@@ -732,6 +810,7 @@ std::vector<std::vector<std::string>> Sol2ScriptingEnvironment::GetExcludableCla
|
||||
auto &context = GetSol2Context();
|
||||
switch (context.api_version)
|
||||
{
|
||||
case 3:
|
||||
case 2:
|
||||
return Sol2ScriptingEnvironment::GetStringListsFromTable("excludable");
|
||||
default:
|
||||
@@ -744,6 +823,7 @@ std::vector<std::string> Sol2ScriptingEnvironment::GetClassNames()
|
||||
auto &context = GetSol2Context();
|
||||
switch (context.api_version)
|
||||
{
|
||||
case 3:
|
||||
case 2:
|
||||
return Sol2ScriptingEnvironment::GetStringListFromTable("classes");
|
||||
default:
|
||||
@@ -756,6 +836,7 @@ std::vector<std::string> Sol2ScriptingEnvironment::GetNameSuffixList()
|
||||
auto &context = GetSol2Context();
|
||||
switch (context.api_version)
|
||||
{
|
||||
case 3:
|
||||
case 2:
|
||||
return Sol2ScriptingEnvironment::GetStringListFromTable("suffix_list");
|
||||
case 1:
|
||||
@@ -770,6 +851,7 @@ std::vector<std::string> Sol2ScriptingEnvironment::GetRestrictions()
|
||||
auto &context = GetSol2Context();
|
||||
switch (context.api_version)
|
||||
{
|
||||
case 3:
|
||||
case 2:
|
||||
return Sol2ScriptingEnvironment::GetStringListFromTable("restrictions");
|
||||
case 1:
|
||||
@@ -785,6 +867,7 @@ void Sol2ScriptingEnvironment::ProcessTurn(ExtractionTurn &turn)
|
||||
|
||||
switch (context.api_version)
|
||||
{
|
||||
case 3:
|
||||
case 2:
|
||||
if (context.has_turn_penalty_function)
|
||||
{
|
||||
@@ -851,6 +934,7 @@ void Sol2ScriptingEnvironment::ProcessSegment(ExtractionSegment &segment)
|
||||
{
|
||||
switch (context.api_version)
|
||||
{
|
||||
case 3:
|
||||
case 2:
|
||||
context.segment_function(context.profile_table, segment);
|
||||
break;
|
||||
@@ -866,12 +950,17 @@ void Sol2ScriptingEnvironment::ProcessSegment(ExtractionSegment &segment)
|
||||
}
|
||||
}
|
||||
|
||||
void LuaScriptingContext::ProcessNode(const osmium::Node &node, ExtractionNode &result)
|
||||
void LuaScriptingContext::ProcessNode(const osmium::Node &node,
|
||||
ExtractionNode &result,
|
||||
const ExtractionRelationContainer::RelationList &relations)
|
||||
{
|
||||
BOOST_ASSERT(state.lua_state() != nullptr);
|
||||
|
||||
switch (api_version)
|
||||
{
|
||||
case 3:
|
||||
node_function(profile_table, node, result, relations);
|
||||
break;
|
||||
case 2:
|
||||
node_function(profile_table, node, result);
|
||||
break;
|
||||
@@ -882,12 +971,17 @@ void LuaScriptingContext::ProcessNode(const osmium::Node &node, ExtractionNode &
|
||||
}
|
||||
}
|
||||
|
||||
void LuaScriptingContext::ProcessWay(const osmium::Way &way, ExtractionWay &result)
|
||||
void LuaScriptingContext::ProcessWay(const osmium::Way &way,
|
||||
ExtractionWay &result,
|
||||
const ExtractionRelationContainer::RelationList &relations)
|
||||
{
|
||||
BOOST_ASSERT(state.lua_state() != nullptr);
|
||||
|
||||
switch (api_version)
|
||||
{
|
||||
case 3:
|
||||
way_function(profile_table, way, result, relations);
|
||||
break;
|
||||
case 2:
|
||||
way_function(profile_table, way, result);
|
||||
break;
|
||||
@@ -897,5 +991,15 @@ void LuaScriptingContext::ProcessWay(const osmium::Way &way, ExtractionWay &resu
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
void LuaScriptingContext::ProcessRelation(const osmium::Relation &relation,
|
||||
ExtractionRelation &result)
|
||||
{
|
||||
BOOST_ASSERT(state.lua_state() != nullptr);
|
||||
BOOST_ASSERT(api_version > 2);
|
||||
|
||||
relation_function(profile_table, relation, result);
|
||||
}
|
||||
}
|
||||
|
||||
} // namespace extractor
|
||||
} // namespace osrm
|
||||
|
||||
+48
-53
@@ -52,46 +52,49 @@ const static unsigned INIT_OK_START_ENGINE = 0;
|
||||
const static unsigned INIT_OK_DO_NOT_START_ENGINE = 1;
|
||||
const static unsigned INIT_FAILED = -1;
|
||||
|
||||
static EngineConfig::Algorithm stringToAlgorithm(std::string algorithm)
|
||||
namespace osrm
|
||||
{
|
||||
boost::to_lower(algorithm);
|
||||
namespace engine
|
||||
{
|
||||
std::istream &operator>>(std::istream &in, EngineConfig::Algorithm &algorithm)
|
||||
{
|
||||
std::string token;
|
||||
in >> token;
|
||||
boost::to_lower(token);
|
||||
|
||||
if (algorithm == "ch")
|
||||
return EngineConfig::Algorithm::CH;
|
||||
if (algorithm == "corech")
|
||||
return EngineConfig::Algorithm::CoreCH;
|
||||
if (algorithm == "mld")
|
||||
return EngineConfig::Algorithm::MLD;
|
||||
throw util::RuntimeError(algorithm, ErrorCode::UnknownAlgorithm, SOURCE_REF);
|
||||
if (token == "ch")
|
||||
algorithm = EngineConfig::Algorithm::CH;
|
||||
else if (token == "corech")
|
||||
algorithm = EngineConfig::Algorithm::CoreCH;
|
||||
else if (token == "mld")
|
||||
algorithm = EngineConfig::Algorithm::MLD;
|
||||
else
|
||||
throw util::RuntimeError(token, ErrorCode::UnknownAlgorithm, SOURCE_REF);
|
||||
return in;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// generate boost::program_options object for the routing part
|
||||
inline unsigned generateServerProgramOptions(const int argc,
|
||||
const char *argv[],
|
||||
std::string verbosity,
|
||||
boost::filesystem::path &base_path,
|
||||
std::string &ip_address,
|
||||
int &ip_port,
|
||||
int &requested_num_threads,
|
||||
bool &use_shared_memory,
|
||||
std::string &algorithm,
|
||||
bool &trial,
|
||||
int &max_locations_trip,
|
||||
int &max_locations_viaroute,
|
||||
int &max_locations_distance_table,
|
||||
int &max_locations_map_matching,
|
||||
int &max_results_nearest,
|
||||
int &max_alternatives)
|
||||
EngineConfig &config)
|
||||
{
|
||||
using boost::program_options::value;
|
||||
using boost::filesystem::path;
|
||||
|
||||
const auto hardware_threads = std::max<int>(1, std::thread::hardware_concurrency());
|
||||
|
||||
// declare a group of options that will be allowed only on command line
|
||||
boost::program_options::options_description generic_options("Options");
|
||||
generic_options.add_options() //
|
||||
("version,v", "Show version")("help,h", "Show this help message")(
|
||||
"verbosity,l",
|
||||
boost::program_options::value<std::string>(&verbosity)->default_value("INFO"),
|
||||
boost::program_options::value<std::string>(&config.verbosity)->default_value("INFO"),
|
||||
std::string("Log verbosity level: " + util::LogPolicy::GetLevels()).c_str())(
|
||||
"trial", value<bool>(&trial)->implicit_value(true), "Quit after initialization");
|
||||
|
||||
@@ -105,31 +108,32 @@ inline unsigned generateServerProgramOptions(const int argc,
|
||||
value<int>(&ip_port)->default_value(5000),
|
||||
"TCP/IP port") //
|
||||
("threads,t",
|
||||
value<int>(&requested_num_threads)->default_value(8),
|
||||
value<int>(&config.use_threads_number)->default_value(hardware_threads),
|
||||
"Number of threads to use") //
|
||||
("shared-memory,s",
|
||||
value<bool>(&use_shared_memory)->implicit_value(true)->default_value(false),
|
||||
value<bool>(&config.use_shared_memory)->implicit_value(true)->default_value(false),
|
||||
"Load data from shared memory") //
|
||||
("algorithm,a",
|
||||
value<std::string>(&algorithm)->default_value("CH"),
|
||||
value<EngineConfig::Algorithm>(&config.algorithm)
|
||||
->default_value(EngineConfig::Algorithm::CH, "CH"),
|
||||
"Algorithm to use for the data. Can be CH, CoreCH, MLD.") //
|
||||
("max-viaroute-size",
|
||||
value<int>(&max_locations_viaroute)->default_value(500),
|
||||
value<int>(&config.max_locations_viaroute)->default_value(500),
|
||||
"Max. locations supported in viaroute query") //
|
||||
("max-trip-size",
|
||||
value<int>(&max_locations_trip)->default_value(100),
|
||||
value<int>(&config.max_locations_trip)->default_value(100),
|
||||
"Max. locations supported in trip query") //
|
||||
("max-table-size",
|
||||
value<int>(&max_locations_distance_table)->default_value(100),
|
||||
value<int>(&config.max_locations_distance_table)->default_value(100),
|
||||
"Max. locations supported in distance table query") //
|
||||
("max-matching-size",
|
||||
value<int>(&max_locations_map_matching)->default_value(100),
|
||||
value<int>(&config.max_locations_map_matching)->default_value(100),
|
||||
"Max. locations supported in map matching query") //
|
||||
("max-nearest-size",
|
||||
value<int>(&max_results_nearest)->default_value(100),
|
||||
value<int>(&config.max_results_nearest)->default_value(100),
|
||||
"Max. results supported in nearest query") //
|
||||
("max-alternatives",
|
||||
value<int>(&max_alternatives)->default_value(3),
|
||||
value<int>(&config.max_alternatives)->default_value(3),
|
||||
"Max. number of alternatives supported in the MLD route query");
|
||||
|
||||
// hidden options, will be allowed on command line, but will not be shown to the user
|
||||
@@ -180,19 +184,22 @@ inline unsigned generateServerProgramOptions(const int argc,
|
||||
|
||||
boost::program_options::notify(option_variables);
|
||||
|
||||
if (!use_shared_memory && option_variables.count("base"))
|
||||
if (!config.use_shared_memory && option_variables.count("base"))
|
||||
{
|
||||
return INIT_OK_START_ENGINE;
|
||||
}
|
||||
else if (use_shared_memory && !option_variables.count("base"))
|
||||
else if (config.use_shared_memory && !option_variables.count("base"))
|
||||
{
|
||||
return INIT_OK_START_ENGINE;
|
||||
}
|
||||
else if (use_shared_memory && option_variables.count("base"))
|
||||
else if (config.use_shared_memory && option_variables.count("base"))
|
||||
{
|
||||
util::Log(logWARNING) << "Shared memory settings conflict with path settings.";
|
||||
}
|
||||
|
||||
// Adjust number of threads to hardware concurrency
|
||||
config.use_threads_number = std::min(hardware_threads, config.use_threads_number);
|
||||
|
||||
std::cout << visible_options;
|
||||
return INIT_OK_DO_NOT_START_ENGINE;
|
||||
}
|
||||
@@ -203,28 +210,13 @@ int main(int argc, const char *argv[]) try
|
||||
|
||||
bool trial_run = false;
|
||||
std::string ip_address;
|
||||
int ip_port, requested_thread_num;
|
||||
int ip_port;
|
||||
|
||||
EngineConfig config;
|
||||
std::string verbosity;
|
||||
boost::filesystem::path base_path;
|
||||
std::string algorithm;
|
||||
const unsigned init_result = generateServerProgramOptions(argc,
|
||||
argv,
|
||||
verbosity,
|
||||
base_path,
|
||||
ip_address,
|
||||
ip_port,
|
||||
requested_thread_num,
|
||||
config.use_shared_memory,
|
||||
algorithm,
|
||||
trial_run,
|
||||
config.max_locations_trip,
|
||||
config.max_locations_viaroute,
|
||||
config.max_locations_distance_table,
|
||||
config.max_locations_map_matching,
|
||||
config.max_results_nearest,
|
||||
config.max_alternatives);
|
||||
|
||||
const unsigned init_result =
|
||||
generateServerProgramOptions(argc, argv, base_path, ip_address, ip_port, trial_run, config);
|
||||
if (init_result == INIT_OK_DO_NOT_START_ENGINE)
|
||||
{
|
||||
return EXIT_SUCCESS;
|
||||
@@ -234,7 +226,7 @@ int main(int argc, const char *argv[]) try
|
||||
return EXIT_FAILURE;
|
||||
}
|
||||
|
||||
util::LogPolicy::GetInstance().SetLevel(verbosity);
|
||||
util::LogPolicy::GetInstance().SetLevel(config.verbosity);
|
||||
|
||||
if (!base_path.empty())
|
||||
{
|
||||
@@ -253,7 +245,6 @@ int main(int argc, const char *argv[]) try
|
||||
}
|
||||
return EXIT_FAILURE;
|
||||
}
|
||||
config.algorithm = stringToAlgorithm(algorithm);
|
||||
|
||||
util::Log() << "starting up engines, " << OSRM_VERSION;
|
||||
|
||||
@@ -262,6 +253,10 @@ int main(int argc, const char *argv[]) try
|
||||
util::Log() << "Loading from shared memory";
|
||||
}
|
||||
|
||||
// Use the same number of threads for Server and TBB threads pools
|
||||
// It doubles number of used threads
|
||||
auto requested_thread_num = config.use_threads_number;
|
||||
|
||||
util::Log() << "Threads: " << requested_thread_num;
|
||||
util::Log() << "IP address: " << ip_address;
|
||||
util::Log() << "IP port: " << ip_port;
|
||||
|
||||
@@ -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
|
||||
+1
-1
@@ -48,7 +48,7 @@ void LogPolicy::SetLevel(std::string const &level)
|
||||
else if (boost::iequals(level, "DEBUG"))
|
||||
m_level = logDEBUG;
|
||||
else
|
||||
;
|
||||
m_level = logINFO;
|
||||
}
|
||||
|
||||
LogPolicy &LogPolicy::GetInstance()
|
||||
|
||||
+26
-23
@@ -144,29 +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": "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"},
|
||||
|
||||
+1
-1
@@ -1 +1 @@
|
||||
n1 v1 dV c1 t2014-01-01T00:00:00Z i1 utest T x1.02 y1.02
|
||||
n1 v1 dV c1 t2014-01-01T00:00:00Z i1 utest T x1.02 y1.02
|
||||
|
||||
@@ -34,11 +34,14 @@ class MockScriptingEnvironment : public extractor::ScriptingEnvironment
|
||||
void ProcessTurn(extractor::ExtractionTurn &) override final {}
|
||||
void ProcessSegment(extractor::ExtractionSegment &) override final {}
|
||||
|
||||
void ProcessElements(const osmium::memory::Buffer &,
|
||||
const extractor::RestrictionParser &,
|
||||
std::vector<std::pair<const osmium::Node &, extractor::ExtractionNode>> &,
|
||||
std::vector<std::pair<const osmium::Way &, extractor::ExtractionWay>> &,
|
||||
std::vector<extractor::InputConditionalTurnRestriction> &) override final
|
||||
void ProcessElements(
|
||||
const osmium::memory::Buffer &,
|
||||
const extractor::RestrictionParser &,
|
||||
const extractor::ExtractionRelationContainer &,
|
||||
std::vector<std::pair<const osmium::Node &, extractor::ExtractionNode>> &,
|
||||
std::vector<std::pair<const osmium::Way &, extractor::ExtractionWay>> &,
|
||||
std::vector<std::pair<const osmium::Relation &, extractor::ExtractionRelation>> &,
|
||||
std::vector<extractor::InputConditionalTurnRestriction> &) override final
|
||||
{
|
||||
}
|
||||
};
|
||||
|
||||
Reference in New Issue
Block a user