Compare commits

..

1 Commits

Author SHA1 Message Date
Daniel Patterson 3fdecc79f4 Bump CMakeLists version. 2016-11-08 16:07:56 -08:00
421 changed files with 10488 additions and 18014 deletions
-7
View File
@@ -1,7 +0,0 @@
{
"presets": [
"stage-0",
"es2015",
"react"
]
}
+45 -57
View File
@@ -25,8 +25,7 @@ env:
- CCACHE_TEMPDIR=/tmp/.ccache-temp
- CCACHE_COMPRESS=1
- CASHER_TIME_OUT=599 # one second less than 10m to avoid 10m timeout error: https://github.com/Project-OSRM/osrm-backend/issues/2742
- CCACHE_VERSION=3.3.1
- CMAKE_VERSION=3.6.2
- JOBS=4
matrix:
fast_finish: true
@@ -40,7 +39,7 @@ matrix:
addons: &gcc6
apt:
sources: ['ubuntu-toolchain-r-test']
packages: ['g++-6', 'libbz2-dev', 'libstxxl-dev', 'libstxxl1', 'libxml2-dev', 'libzip-dev', 'lua5.1', 'liblua5.1-0-dev', 'libtbb-dev', 'libgdal-dev', 'libluabind-dev', 'libboost-all-dev']
packages: ['g++-6', 'libbz2-dev', 'libstxxl-dev', 'libstxxl1', 'libxml2-dev', 'libzip-dev', 'lua5.1', 'liblua5.1-0-dev', 'libtbb-dev', 'libgdal-dev', 'libluabind-dev', 'libboost-all-dev', 'ccache']
env: CCOMPILER='gcc-6' CXXCOMPILER='g++-6' BUILD_TYPE='Debug' TARGET_ARCH='x86_64-asan' ENABLE_COVERAGE=ON ENABLE_SANITIZER=ON BUILD_COMPONENTS=ON
- os: linux
@@ -48,45 +47,34 @@ matrix:
addons: &clang38
apt:
sources: ['ubuntu-toolchain-r-test']
packages: ['libstdc++-5-dev', 'libbz2-dev', 'libstxxl-dev', 'libstxxl1', 'libxml2-dev', 'libzip-dev', 'lua5.1', 'liblua5.1-0-dev', 'libtbb-dev', 'libgdal-dev', 'libluabind-dev', 'libboost-all-dev']
env: CLANG_VERSION='3.8.1' BUILD_TYPE='Debug' RUN_CLANG_FORMAT=ON BUILD_COMPONENTS=ON CUCUMBER_TIMEOUT=60000
packages: ['libstdc++-5-dev', 'libbz2-dev', 'libstxxl-dev', 'libstxxl1', 'libxml2-dev', 'libzip-dev', 'lua5.1', 'liblua5.1-0-dev', 'libtbb-dev', 'libgdal-dev', 'libluabind-dev', 'libboost-all-dev', 'ccache']
env: CLANG_VERSION='3.8.1' CLANG_PACKAGE="clang++" BUILD_TYPE='Debug' RUN_CLANG_FORMAT=ON BUILD_COMPONENTS=ON CUCUMBER_TIMEOUT=60000
- os: osx
osx_image: xcode8.2
compiler: "mason-osx-release"
# we use the xcode provides clang and don't install our own
env: ENABLE_MASON=ON BUILD_TYPE='Release' CUCUMBER_TIMEOUT=60000 CCOMPILER='clang' CXXCOMPILER='clang++' ENABLE_ASSERTIONS=ON
osx_image: xcode7.3
compiler: clang
env: CCOMPILER='clang' CXXCOMPILER='clang++' BUILD_TYPE='Debug' JOBS=1 CUCUMBER_TIMEOUT=60000
# Release Builds
- os: linux
compiler: "mason-linux-release"
compiler: "mason-release"
addons:
apt:
sources: ['ubuntu-toolchain-r-test']
packages: ['libstdc++-5-dev']
env: CLANG_VERSION='3.8.1' BUILD_TYPE='Release' ENABLE_MASON=ON
packages: ['libstdc++-5-dev', 'ccache']
env: BUILD_TYPE='Release' ENABLE_MASON=ON
- os: linux
compiler: "gcc-6-release"
addons: &gcc6
apt:
sources: ['ubuntu-toolchain-r-test']
packages: ['g++-6', 'libbz2-dev', 'libstxxl-dev', 'libstxxl1', 'libxml2-dev', 'libzip-dev', 'lua5.1', 'liblua5.1-0-dev', 'libtbb-dev', 'libgdal-dev', 'libluabind-dev', 'libboost-all-dev']
packages: ['g++-6', 'libbz2-dev', 'libstxxl-dev', 'libstxxl1', 'libxml2-dev', 'libzip-dev', 'lua5.1', 'liblua5.1-0-dev', 'libtbb-dev', 'libgdal-dev', 'libluabind-dev', 'libboost-all-dev', 'ccache']
env: CCOMPILER='gcc-6' CXXCOMPILER='g++-6' BUILD_TYPE='Release' BUILD_COMPONENTS=ON
- os: linux
compiler: "gcc-6-release-i686"
env: >
TARGET_ARCH='i686' CCOMPILER='gcc-6' CXXCOMPILER='g++-6' BUILD_TYPE='Release'
CFLAGS='-m32 -msse2 -mfpmath=sse' CXXFLAGS='-m32 -msse2 -mfpmath=sse'
- os: linux
compiler: "gcc-4.9-release"
addons: &gcc49
apt:
sources: ['ubuntu-toolchain-r-test']
packages: ['g++-4.9', 'libbz2-dev', 'libstxxl-dev', 'libstxxl1', 'libxml2-dev', 'libzip-dev', 'lua5.1', 'liblua5.1-0-dev', 'libtbb-dev', 'libgdal-dev', 'libluabind-dev', 'libboost-all-dev', 'ccache']
env: CCOMPILER='gcc-4.9' CXXCOMPILER='g++-4.9' BUILD_TYPE='Release'
env: TARGET_ARCH='i686' CCOMPILER='gcc-6' CXXCOMPILER='g++-6' BUILD_TYPE='Release'
# Disabled because of CI slowness
#- os: linux
@@ -97,13 +85,19 @@ matrix:
#- packages: ['clang-3.8', 'libbz2-dev', 'libstxxl-dev', 'libstxxl1', 'libxml2-dev', 'libzip-dev', 'lua5.1', 'liblua5.1-0-dev', 'libtbb-dev', 'libgdal-dev', 'libluabind-dev', 'libboost-all-dev']
#- env: CCOMPILER='clang-3.8' CXXCOMPILER='clang++-3.8' BUILD_TYPE='Release'
# Disabled because of CI slowness
#- os: osx
#- osx_image: xcode7.3
#- compiler: clang
#- env: CCOMPILER='clang' CXXCOMPILER='clang++' BUILD_TYPE='Release'
# Shared Library
- os: linux
compiler: "gcc-6-release-shared"
addons: &gcc6
apt:
sources: ['ubuntu-toolchain-r-test']
packages: ['g++-6', 'libbz2-dev', 'libstxxl-dev', 'libstxxl1', 'libxml2-dev', 'libzip-dev', 'lua5.1', 'liblua5.1-0-dev', 'libtbb-dev', 'libgdal-dev', 'libluabind-dev', 'libboost-all-dev']
packages: ['g++-6', 'libbz2-dev', 'libstxxl-dev', 'libstxxl1', 'libxml2-dev', 'libzip-dev', 'lua5.1', 'liblua5.1-0-dev', 'libtbb-dev', 'libgdal-dev', 'libluabind-dev', 'libboost-all-dev', 'ccache']
env: CCOMPILER='gcc-6' CXXCOMPILER='g++-6' BUILD_TYPE='Release' BUILD_SHARED_LIBS=ON BUILD_COMPONENTS=ON
# Disabled because CI slowness
@@ -117,36 +111,24 @@ matrix:
before_install:
- if [[ ! -z $TARGET_ARCH ]] ; then source ./scripts/travis/before_install.$TARGET_ARCH.sh ; fi
- if [[ $(uname -s) == 'Darwin' ]]; then sudo mdutil -i off /; fi;
- source ./scripts/install_node.sh 4
- npm install
- DEPS_DIR="${TRAVIS_BUILD_DIR}/deps"
- export PATH=${DEPS_DIR}/bin:${PATH} && mkdir -p ${DEPS_DIR}
- CMAKE_URL="https://mason-binaries.s3.amazonaws.com/${TRAVIS_OS_NAME}-x86_64/cmake/3.5.2.tar.gz"
- travis_retry wget --quiet -O - ${CMAKE_URL} | tar --strip-components=1 -xz -C ${DEPS_DIR} || exit 1
- |
if [[ "${TRAVIS_OS_NAME}" == "linux" ]]; then
export JOBS=$((`nproc` + 1))
if [[ ${CLANG_VERSION:-false} != false ]]; then
export CCOMPILER='clang'
export CXXCOMPILER='clang++'
CLANG_URL="https://mason-binaries.s3.amazonaws.com/${TRAVIS_OS_NAME}-x86_64/${CLANG_PACKAGE}/${CLANG_VERSION}.tar.gz"
travis_retry wget --quiet -O - ${CLANG_URL} | tar --strip-components=1 -xz -C ${DEPS_DIR} || exit 1
fi
- |
if [[ "${TRAVIS_OS_NAME}" == "osx" ]]; then
export JOBS=$((`sysctl -n hw.ncpu` + 1))
sudo mdutil -i off /
fi
- echo "Using ${JOBS} jobs"
- source ./scripts/install_node.sh 4
- npm install -g "npm@>=3" # Upgrade to npm >v2 to reduce size of downloaded dependencies
- npm install
- ./third_party/mason/mason install ccache ${CCACHE_VERSION}
- export PATH=$(./third_party/mason/mason prefix ccache ${CCACHE_VERSION})/bin:${PATH}
- ./third_party/mason/mason install cmake ${CMAKE_VERSION}
- export PATH=$(./third_party/mason/mason prefix cmake ${CMAKE_VERSION})/bin:${PATH}
- |
if [[ ! -z ${CLANG_VERSION} ]]; then
export CCOMPILER='clang'
export CXXCOMPILER='clang++'
./third_party/mason/mason install clang++ ${CLANG_VERSION}
export PATH=$(./third_party/mason/mason prefix clang++ ${CLANG_VERSION})/bin:${PATH}
# we only enable lto for release builds
# and therefore don't need to us ld.gold or llvm tools for linking
# for debug builds
if [[ ${BUILD_TYPE} == 'Release' ]]; then
./third_party/mason/mason install binutils 2.27
export PATH=$(./third_party/mason/mason prefix binutils 2.27)/bin:${PATH}
fi
# implicit deps, but seem to be installed by default with recent images: libxml2 GDAL boost
brew install libzip libstxxl lua51 luabind tbb md5sha1sum ccache
fi
- ccache --max-size=256M # limiting the cache's size to roughly the previous job's object sizes
@@ -155,11 +137,11 @@ install:
if [[ "${TRAVIS_OS_NAME}" == "linux" ]]; then
./scripts/check_taginfo.py taginfo.json profiles/car.lua
fi
- export OSRM_BUILD_DIR="$(pwd)/build-osrm"
- mkdir ${OSRM_BUILD_DIR} && pushd ${OSRM_BUILD_DIR}
- mkdir build && pushd build
- export CC=${CCOMPILER} CXX=${CXXCOMPILER}
- cmake .. -DCMAKE_BUILD_TYPE=${BUILD_TYPE} -DENABLE_MASON=${ENABLE_MASON:-OFF} -DENABLE_ASSERTIONS=${ENABLE_ASSERTIONS:-OFF} -DBUILD_SHARED_LIBS=${BUILD_SHARED_LIBS:-OFF} -DENABLE_COVERAGE=${ENABLE_COVERAGE:-OFF} -DENABLE_SANITIZER=${ENABLE_SANITIZER:-OFF} -DBUILD_TOOLS=ON -DBUILD_COMPONENTS=${BUILD_COMPONENTS:-OFF} -DENABLE_CCACHE=ON
- cmake .. -DCMAKE_BUILD_TYPE=${BUILD_TYPE} -DENABLE_MASON=${ENABLE_MASON:-OFF} -DBUILD_SHARED_LIBS=${BUILD_SHARED_LIBS:-OFF} -DENABLE_COVERAGE=${ENABLE_COVERAGE:-OFF} -DENABLE_SANITIZER=${ENABLE_SANITIZER:-OFF} -DBUILD_TOOLS=ON -DBUILD_COMPONENTS=${BUILD_COMPONENTS:-OFF} -DENABLE_CCACHE=ON
- echo "travis_fold:start:MAKE"
- make osrm-extract --jobs=3
- make --jobs=${JOBS}
- make tests --jobs=${JOBS}
- make benchmarks --jobs=${JOBS}
@@ -171,11 +153,17 @@ install:
sudo ldconfig
fi
- popd
- |
if [[ ${ENABLE_MASON:-OFF} == 'ON' ]]; then
# for mason builds we need to point the example
# at the clang++ installed by the CMakeLists.txt automatically
export CXX=$(./third_party/mason/mason prefix clang++ 3.8.1)/bin/clang++
export CC=$(./third_party/mason/mason prefix clang++ 3.8.1)/bin/clang
fi
- mkdir example/build && pushd example/build
- cmake .. -DCMAKE_BUILD_TYPE=${BUILD_TYPE}
- make --jobs=${JOBS}
- make
- popd
- npm run build-api-docs
script:
- if [[ $TARGET_ARCH == armhf ]] ; then echo "Skip tests for $TARGET_ARCH" && exit 0 ; fi
@@ -184,7 +172,7 @@ script:
- echo "travis_fold:end:BENCHMARK"
- ./example/build/osrm-example test/data/monaco.osrm
# All tests assume to be run from the build directory
- pushd ${OSRM_BUILD_DIR}
- pushd build
- ./unit_tests/library-tests ../test/data/monaco.osrm
- ./unit_tests/extractor-tests
- ./unit_tests/engine-tests
-14
View File
@@ -5,10 +5,6 @@
- Shared memory now allows for multiple clients (multiple instances of libosrm on the same segment)
- Polyline geometries can now be requested with precision 5 as well as with precision 6
- Profiles
- the car profile has been refactored into smaller functions
- get_value_by_key() is now guaranteed never to return empty strings, nil is returned instead.
- debug.lua was added to make it easier to test/develop profile code.
- `car.lua` now depends on lib/set.lua and lib/sequence.lua
- `restrictions` is now used for namespaced restrictions and restriction exceptions (e.g. `restriction:motorcar=` as well as `except=motorcar`)
- replaced lhs/rhs profiles by using test defined profiles
- Handle `oneway=alternating` (routed over with penalty) separately from `oneway=reversible` (not routed over due to time dependence)
@@ -19,7 +15,6 @@
- Improved turn angle calculation, detecting offsets due to lanes / minor variations due to inaccuracies
- Corrected the bearings returned for intermediate steps - requires reprocessing
- Improved turn locations for collapsed turns
- Sliproad classification refinements: the situations we detect as Sliproads now resemble more closely the reality
- Trip Plugin
- changed internal behaviour to prefer the smallest lexicographic result over the largest one
- Bugfixes
@@ -27,17 +22,8 @@
- fixed compile errors in tile unit-test framework
- fixed a bug that could result in inconsistent behaviour when collapsing instructions
- fixed a bug that could result in crashes when leaving a ferry directly onto a motorway ramp
- fixed a bug in the tile plugin that resulted in discovering invalid edges for connections
- improved error messages when missing files during traffic updates (#3114)
- For single coordinate geometries the GeoJSON `Point` encoding was broken. We now always emit `LineString`s even in the one-coordinate-case (backwards compatible) (#3425)
- Debug Tiles
- Added support for turn penalties
- Internals
- Internal/Shared memory datafacades now share common memory layout and data loading code
- File reading now has much better error handling
- Misc
- Progress indicators now print newlines when stdout is not a TTY
- Prettier API documentation now generated via `npm run build-api-docs` output `build/docs`
# 5.4.3
- Changes from 5.4.2
+63 -133
View File
@@ -7,13 +7,6 @@ Please create a directory and run cmake from there, passing the path to this sou
This process created the file `CMakeCache.txt' and the directory `CMakeFiles'. Please delete them.")
endif()
# detect if this is included as subproject and if so expose
# some variables to its parent scope
get_directory_property(BUILD_AS_SUBPROJECT PARENT_DIRECTORY)
if(BUILD_AS_SUBPROJECT)
message(STATUS "Building libosrm as subproject.")
endif()
option(ENABLE_MASON "Use mason for dependencies" OFF)
option(ENABLE_CCACHE "Speed up incremental rebuilds via ccache" ON)
option(BUILD_TOOLS "Build OSRM tools" OFF)
@@ -26,47 +19,43 @@ option(ENABLE_FUZZING "Fuzz testing using LLVM's libFuzzer" OFF)
option(ENABLE_GOLD_LINKER "Use GNU gold linker if available" ON)
if(ENABLE_MASON)
# versions in use
set(MASON_CLANG_VERSION "3.8.1")
set(MASON_BOOST_VERSION "1.61.0")
set(MASON_STXXL_VERSION "1.4.1")
set(MASON_EXPAT_VERSION "2.2.0")
set(MASON_EXPAT_VERSION "2.1.1")
set(MASON_LUA_VERSION "5.2.4")
set(MASON_LUABIND_VERSION "e414c57bcb687bb3091b7c55bbff6947f052e46b")
set(MASON_BZIP2_VERSION "1.0.6")
set(MASON_TBB_VERSION "43_20150316")
set(MASON_CCACHE_VERSION "3.3.1")
message(STATUS "Enabling mason")
find_program(CURL_FOUND curl)
if(NOT CURL_FOUND)
message(FATAL_ERROR "curl command required with -DENABLE_MASON")
endif()
set(MASON_COMMAND ${CMAKE_CURRENT_SOURCE_DIR}/third_party/mason/mason)
include(${CMAKE_CURRENT_SOURCE_DIR}/third_party/mason/mason.cmake)
if(NOT CMAKE_CXX_COMPILER)
mason_use(clang++ VERSION ${MASON_CLANG_VERSION})
message(STATUS "Setting compiler to clang++ ${MASON_CLANG_VERSION} (via mason) ${MASON_PACKAGE_clang++_PREFIX}/bin/clang++")
set(CMAKE_CXX_COMPILER "${MASON_PACKAGE_clang++_PREFIX}/bin/clang++")
set(CMAKE_C_COMPILER "${MASON_PACKAGE_clang++_PREFIX}/bin/clang")
endif()
endif()
# be compatible with version handling before cmake 3.x
if (POLICY CMP0048)
cmake_policy(SET CMP0048 OLD)
endif()
project(OSRM C CXX)
set(OSRM_VERSION_MAJOR 5)
set(OSRM_VERSION_MINOR 5)
set(OSRM_VERSION_PATCH 0)
set(OSRM_VERSION "${OSRM_VERSION_MAJOR}.${OSRM_VERSION_MINOR}.${OSRM_VERSION_PATCH}")
add_definitions(-DOSRM_PROJECT_DIR="${CMAKE_CURRENT_SOURCE_DIR}")
# these two functions build up custom variables:
# DEPENDENCIES_INCLUDE_DIRS and OSRM_DEFINES
# OSRM_INCLUDE_PATHS and OSRM_DEFINES
# These variables we want to pass to
# include_directories and add_definitions for both
# this build and for sharing externally via pkg-config
function(add_dependency_includes includes)
list(APPEND DEPENDENCIES_INCLUDE_DIRS "${includes}")
set(DEPENDENCIES_INCLUDE_DIRS "${DEPENDENCIES_INCLUDE_DIRS}" PARENT_SCOPE)
list(APPEND OSRM_INCLUDE_PATHS "${includes}")
set(OSRM_INCLUDE_PATHS "${OSRM_INCLUDE_PATHS}" PARENT_SCOPE)
endfunction(add_dependency_includes)
function(add_dependency_defines defines)
@@ -94,7 +83,7 @@ endif()
include_directories(BEFORE ${CMAKE_CURRENT_BINARY_DIR}/include/)
include_directories(BEFORE ${CMAKE_CURRENT_SOURCE_DIR}/include/)
include_directories(SYSTEM ${CMAKE_CURRENT_SOURCE_DIR}/third_party/variant/include)
include_directories(SYSTEM ${CMAKE_CURRENT_SOURCE_DIR}/third_party/)
add_custom_target(FingerPrintConfigure ALL ${CMAKE_COMMAND}
"-DOUTPUT_DIR=${CMAKE_CURRENT_BINARY_DIR}"
@@ -140,7 +129,6 @@ if(ENABLE_GOLD_LINKER)
if("${LD_VERSION}" MATCHES "GNU gold")
set(CMAKE_EXE_LINKER_FLAGS "${CMAKE_EXE_LINKER_FLAGS} -fuse-ld=gold -Wl,--disable-new-dtags")
set(CMAKE_SHARED_LINKER_FLAGS "${CMAKE_EXE_LINKER_FLAGS} -fuse-ld=gold -Wl,--disable-new-dtags")
set(OSRM_LDFLAGS "${OSRM_LDFLAGS} -fuse-ld=gold -Wl,--disable-new-dtags")
message(STATUS "Using GNU gold as linker.")
# Issue 2785: check gold binutils version and don't use gc-sections for versions prior 2.25
@@ -195,8 +183,7 @@ endif()
if(CMAKE_BUILD_TYPE MATCHES Release OR CMAKE_BUILD_TYPE MATCHES MinRelSize OR CMAKE_BUILD_TYPE MATCHES RelWithDebInfo)
message(STATUS "Configuring release mode optimizations")
# Check if LTO is available
check_cxx_compiler_flag("-Wl,-flto" LTO_AVAILABLE)
check_cxx_compiler_flag("-flto" LTO_AVAILABLE)
if(ENABLE_LTO AND LTO_AVAILABLE)
set(OLD_CXX_FLAGS ${CMAKE_CXX_FLAGS})
# GCC in addition allows parallelizing LTO
@@ -211,57 +198,27 @@ if(CMAKE_BUILD_TYPE MATCHES Release OR CMAKE_BUILD_TYPE MATCHES MinRelSize OR CM
check_cxx_source_compiles("${CHECK_LTO_SRC}" LTO_WORKS)
if(LTO_WORKS)
message(STATUS "LTO working")
set(OSRM_CXXFLAGS "${OSRM_CXXFLAGS} -flto")
set(OSRM_LDFLAGS "${OSRM_LDFLAGS} -flto")
set(CMAKE_EXE_LINKER_FLAGS "${CMAKE_EXE_LINKER_FLAGS} -flto")
set(CMAKE_SHARED_LINKER_FLAGS "${CMAKE_SHARED_LINKER_FLAGS} -flto")
set(CMAKE_MODULE_LINKER_FLAGS "${CMAKE_MODULE_LINKER_FLAGS} -flto")
else()
message(STATUS "LTO broken")
set(CMAKE_CXX_FLAGS "${OLD_CXX_FLAGS}")
set(ENABLE_LTO Off)
endif()
# Since gcc 4.9 the LTO format is non-standart ('slim'), so we need to use the build-in tools
if("${CMAKE_CXX_COMPILER_ID}" STREQUAL "GNU" AND
NOT "${CMAKE_CXX_COMPILER_VERSION}" VERSION_LESS "4.9.0" AND NOT MINGW)
find_program(GCC_AR gcc-ar)
find_program(GCC_RANLIB gcc-ranlib)
if ("${GCC_AR}" STREQUAL "GCC_AR-NOTFOUND" OR "${GCC_RANLIB}" STREQUAL "GCC_RANLIB-NOTFOUND")
message(WARNING "GCC specific binutils not found.")
else()
message(STATUS "Using GCC specific binutils for LTO:")
message(STATUS " ${GCC_AR}")
message(STATUS " ${GCC_RANLIB}")
set(CMAKE_AR ${GCC_AR})
set(CMAKE_RANLIB ${GCC_RANLIB})
endif()
endif()
# Same for clang LTO requires their own toolchain
if("${CMAKE_CXX_COMPILER_ID}" STREQUAL "Clang")
find_program(LLVM_AR llvm-ar)
find_program(LLVM_RANLIB llvm-ranlib)
if ("${LLVM_AR}" STREQUAL "LLVM_AR-NOTFOUND" OR "${LLVM_RANLIB}" STREQUAL "LLVM_RANLIB-NOTFOUND")
message(WARNING "LLVM specific binutils not found.")
else()
message(STATUS "Using LLVM specific binutils for LTO:")
message(STATUS " ${LLVM_AR}")
message(STATUS " ${LLVM_RANLIB}")
set(CMAKE_AR ${LLVM_AR})
set(CMAKE_RANLIB ${LLVM_RANLIB})
endif()
message(STATUS "Using gcc specific binutils for LTO.")
set(CMAKE_AR "/usr/bin/gcc-ar")
set(CMAKE_RANLIB "/usr/bin/gcc-ranlib")
endif()
if("${CMAKE_CXX_COMPILER_ID}" STREQUAL "GNU" AND "${CMAKE_CXX_COMPILER_VERSION}" VERSION_LESS "4.9.0")
message(STATUS "Disabling LTO on GCC < 4.9.0 since it is broken, see: https://gcc.gnu.org/bugzilla/show_bug.cgi?id=57038")
set(CMAKE_CXX_FLAGS "${OLD_CXX_FLAGS}")
set(ENABLE_LTO Off)
endif()
endif()
endif()
if(UNIX AND NOT APPLE AND ENABLE_MASON AND (LTO_WORKS OR ENABLE_GOLD_LINKER))
if (ENABLE_MASON AND (LTO_WORKS OR ENABLE_GOLD_LINKER))
message(WARNING "ENABLE_MASON and ENABLE_LTO/ENABLE_GOLD_LINKER may not work on all linux systems currently")
message(WARNING "For more details see: https://github.com/Project-OSRM/osrm-backend/issues/3202")
endif()
@@ -277,7 +234,6 @@ if (ENABLE_COVERAGE)
endif()
if (ENABLE_SANITIZER)
set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -fsanitize=address")
set(OSRM_CXXFLAGS "${OSRM_CXXFLAGS} -fsanitize=address")
endif()
# Configuring compilers
@@ -324,11 +280,9 @@ if("${LINKER_VERSION}" MATCHES "GNU gold" OR "${LINKER_VERSION}" MATCHES "GNU ld
endif()
# Default linker optimization flags
set(LINKER_FLAGS "${LINKER_FLAGS} -Wl,-O1 -Wl,--hash-style=gnu -Wl,--sort-common")
else()
message(STATUS "Using unknown linker, not setting linker optimizations")
endif ()
set(OSRM_LDFLAGS "${OSRM_LDFLAGS} ${LINKER_FLAGS}")
set(CMAKE_EXE_LINKER_FLAGS "${CMAKE_EXE_LINKER_FLAGS} ${LINKER_FLAGS}")
set(CMAKE_SHARED_LINKER_FLAGS "${CMAKE_SHARED_LINKER_FLAGS} ${LINKER_FLAGS}")
set(CMAKE_MODULE_LINKER_FLAGS "${CMAKE_MODULE_LINKER_FLAGS} ${LINKER_FLAGS}")
@@ -336,7 +290,6 @@ set(CMAKE_MODULE_LINKER_FLAGS "${CMAKE_MODULE_LINKER_FLAGS} ${LINKER_FLAGS}")
# Activate C++1y
if(NOT ${CMAKE_CXX_COMPILER_ID} STREQUAL "MSVC")
set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -std=c++1y")
set(OSRM_CXXFLAGS "${OSRM_CXXFLAGS} -std=c++1y")
endif()
# Configuring other platform dependencies
@@ -418,21 +371,18 @@ if(ENABLE_MASON)
if(NOT MASON_PACKAGE_tbb_LIBRARY_DIRS)
message(FATAL_ERROR "MASON_PACKAGE_tbb_LIBRARY_DIRS is empty, rpath will not work")
endif()
set(TBB_LINKER_RPATHS "")
foreach(libpath ${MASON_PACKAGE_tbb_LIBRARY_DIRS})
set(TBB_LINKER_RPATHS "${TBB_LINKER_RPATHS} -Wl,-rpath -Wl,${libpath}")
if(UNIX AND NOT APPLE)
set(LINKER_FLAGS "-Wl,-rpath,${libpath}")
elseif(APPLE)
set(LINKER_FLAGS "-Wl,-rpath, -Wl,${libpath}")
endif()
set(CMAKE_EXE_LINKER_FLAGS "${CMAKE_EXE_LINKER_FLAGS} ${LINKER_FLAGS}")
set(CMAKE_SHARED_LINKER_FLAGS "${CMAKE_SHARED_LINKER_FLAGS} ${LINKER_FLAGS}")
set(CMAKE_MODULE_LINKER_FLAGS "${CMAKE_MODULE_LINKER_FLAGS} ${LINKER_FLAGS}")
file(GLOB TBBGlob ${libpath}/*.*)
install(FILES ${TBBGlob} DESTINATION lib)
endforeach()
if(APPLE)
set(LINKER_FLAGS "${TBB_LINKER_RPATHS} -Wl,-rpath -Wl,@executable_path")
elseif(UNIX)
set(LINKER_FLAGS "${TBB_LINKER_RPATHS} '-Wl,-rpath,$ORIGIN' -Wl,-z,origin")
endif()
set(CMAKE_EXE_LINKER_FLAGS "${CMAKE_EXE_LINKER_FLAGS} ${LINKER_FLAGS}")
set(CMAKE_SHARED_LINKER_FLAGS "${CMAKE_SHARED_LINKER_FLAGS} ${LINKER_FLAGS}")
set(CMAKE_MODULE_LINKER_FLAGS "${CMAKE_MODULE_LINKER_FLAGS} ${LINKER_FLAGS}")
if(BUILD_COMPONENTS)
message(FATAL_ERROR "BUILD_COMPONENTS is not supported with ENABLE_MASON")
@@ -441,9 +391,14 @@ if(ENABLE_MASON)
# current mason packages target -D_GLIBCXX_USE_CXX11_ABI=0
set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -D_GLIBCXX_USE_CXX11_ABI=0")
# note: we avoid calling find_package(Osmium ...) here to ensure that the
# expat and bzip2 are used from mason rather than the system
include_directories(SYSTEM ${CMAKE_CURRENT_SOURCE_DIR}/third_party/libosmium/include)
if(ENABLE_CCACHE)
mason_use(ccache VERSION ${MASON_CCACHE_VERSION})
message(STATUS "Setting ccache to ccache ${MASON_CCACHE_VERSION} (via mason) ${MASON_PACKAGE_ccache_PREFIX}/bin/ccache")
message(STATUS "Using ccache to speed up incremental builds")
set_property(GLOBAL PROPERTY RULE_LAUNCH_COMPILE ${MASON_PACKAGE_ccache_PREFIX}/bin/ccache)
set_property(GLOBAL PROPERTY RULE_LAUNCH_LINK ${MASON_PACKAGE_ccache_PREFIX}/bin/ccache)
set(ENV{CCACHE_CPP2} "true")
endif()
else()
@@ -484,23 +439,17 @@ else()
)
endif()
# note libosmium depends on expat and bzip2
list(APPEND CMAKE_MODULE_PATH "${CMAKE_CURRENT_SOURCE_DIR}/third_party/libosmium/cmake")
set(OSMIUM_INCLUDE_DIR "${CMAKE_CURRENT_SOURCE_DIR}/third_party/libosmium/include")
find_package(Osmium REQUIRED COMPONENTS io)
include_directories(SYSTEM ${OSMIUM_INCLUDE_DIR})
endif()
# prefix compilation with ccache by default if available and on clang or gcc
if(ENABLE_CCACHE AND (${CMAKE_CXX_COMPILER_ID} STREQUAL "Clang" OR ${CMAKE_CXX_COMPILER_ID} STREQUAL "GNU"))
find_program(CCACHE_FOUND ccache)
if(CCACHE_FOUND)
message(STATUS "Using ccache to speed up incremental builds")
set_property(GLOBAL PROPERTY RULE_LAUNCH_COMPILE ccache)
set_property(GLOBAL PROPERTY RULE_LAUNCH_LINK ccache)
set(ENV{CCACHE_CPP2} "true")
# prefix compilation with ccache by default if available and on clang or gcc
if(ENABLE_CCACHE AND (${CMAKE_CXX_COMPILER_ID} STREQUAL "Clang" OR ${CMAKE_CXX_COMPILER_ID} STREQUAL "GNU"))
find_program(CCACHE_FOUND ccache)
if(CCACHE_FOUND)
message(STATUS "Using ccache to speed up incremental builds")
set_property(GLOBAL PROPERTY RULE_LAUNCH_COMPILE ccache)
set_property(GLOBAL PROPERTY RULE_LAUNCH_LINK ccache)
set(ENV{CCACHE_CPP2} "true")
endif()
endif()
endif()
# even with mason builds we want to link to system zlib
@@ -508,6 +457,11 @@ endif()
find_package(ZLIB REQUIRED)
add_dependency_includes(${ZLIB_INCLUDE_DIRS})
list(APPEND CMAKE_MODULE_PATH "${CMAKE_CURRENT_SOURCE_DIR}/third_party/libosmium/cmake")
set(OSMIUM_INCLUDE_DIR "${CMAKE_CURRENT_SOURCE_DIR}/third_party/libosmium/include")
find_package(Osmium REQUIRED COMPONENTS io)
include_directories(SYSTEM ${OSMIUM_INCLUDE_DIR})
if(NOT WIN32 AND NOT Boost_USE_STATIC_LIBS)
add_dependency_defines(-DBOOST_TEST_DYN_LINK)
endif()
@@ -529,7 +483,7 @@ if(OPENMP_FOUND)
endif()
add_definitions(${OSRM_DEFINES})
include_directories(SYSTEM ${DEPENDENCIES_INCLUDE_DIRS})
include_directories(SYSTEM ${OSRM_INCLUDE_PATHS})
set(BOOST_BASE_LIBRARIES
${Boost_DATE_TIME_LIBRARY}
@@ -545,10 +499,10 @@ set(BOOST_ENGINE_LIBRARIES
${BOOST_BASE_LIBRARIES})
# Binaries
target_link_libraries(osrm-datastore osrm_store ${Boost_PROGRAM_OPTIONS_LIBRARY})
target_link_libraries(osrm-extract osrm_extract ${Boost_PROGRAM_OPTIONS_LIBRARY})
target_link_libraries(osrm-contract osrm_contract ${Boost_PROGRAM_OPTIONS_LIBRARY})
target_link_libraries(osrm-routed osrm ${Boost_PROGRAM_OPTIONS_LIBRARY} ${OPTIONAL_SOCKET_LIBS} ${ZLIB_LIBRARY})
target_link_libraries(osrm-datastore osrm_store ${Boost_PROGRAM_OPTIONS_LIBRARY} ${BOOST_BASE_LIBRARIES})
target_link_libraries(osrm-extract osrm_extract ${Boost_PROGRAM_OPTIONS_LIBRARY} ${Boost_REGEX_LIBRARY} ${BOOST_BASE_LIBRARIES})
target_link_libraries(osrm-contract ${Boost_PROGRAM_OPTIONS_LIBRARY} ${BOOST_BASE_LIBRARIES} ${TBB_LIBRARIES} osrm_contract)
target_link_libraries(osrm-routed osrm ${Boost_PROGRAM_OPTIONS_LIBRARY} ${BOOST_ENGINE_LIBRARIES} ${OPTIONAL_SOCKET_LIBS} ${ZLIB_LIBRARY})
set(EXTRACTOR_LIBRARIES
${BZIP2_LIBRARIES}
@@ -639,7 +593,7 @@ set_property(TARGET osrm-contract PROPERTY INSTALL_RPATH_USE_LINK_PATH TRUE)
set_property(TARGET osrm-datastore PROPERTY INSTALL_RPATH_USE_LINK_PATH TRUE)
set_property(TARGET osrm-routed PROPERTY INSTALL_RPATH_USE_LINK_PATH TRUE)
file(GLOB VariantGlob third_party/variant/include/mapbox/*.hpp)
file(GLOB VariantGlob third_party/variant/*.hpp)
file(GLOB LibraryGlob include/osrm/*.hpp)
file(GLOB ParametersGlob include/engine/api/*_parameters.hpp)
set(EngineHeader include/engine/status.hpp include/engine/engine_config.hpp include/engine/hint.hpp include/engine/bearing.hpp include/engine/phantom_node.hpp)
@@ -654,7 +608,7 @@ install(FILES ${ExtractorHeader} DESTINATION include/osrm/extractor)
install(FILES ${ContractorHeader} DESTINATION include/osrm/contractor)
install(FILES ${LibraryGlob} DESTINATION include/osrm)
install(FILES ${ParametersGlob} DESTINATION include/osrm/engine/api)
install(FILES ${VariantGlob} DESTINATION include/mapbox)
install(FILES ${VariantGlob} DESTINATION include/variant)
install(TARGETS osrm-extract DESTINATION bin)
install(TARGETS osrm-contract DESTINATION bin)
install(TARGETS osrm-datastore DESTINATION bin)
@@ -664,8 +618,9 @@ install(TARGETS osrm_extract DESTINATION lib)
install(TARGETS osrm_contract DESTINATION lib)
install(TARGETS osrm_store DESTINATION lib)
# Setup exporting variables for pkgconfig and subproject
#
foreach(lib ${ENGINE_LIBRARIES})
set(ENGINE_LIBRARY_LISTING "${ENGINE_LIBRARY_LISTING} ${lib}")
endforeach()
if(BUILD_DEBIAN_PACKAGE)
include(CPackDebianConfig)
@@ -677,33 +632,9 @@ function(JOIN VALUES GLUE OUTPUT)
set (${OUTPUT} "${_TMP_STR}" PARENT_SCOPE)
endfunction()
JOIN("${OSRM_DEFINES}" " " TMP_OSRM_DEFINES)
set(LibOSRM_CXXFLAGS "${OSRM_CXXFLAGS} ${TMP_OSRM_DEFINES}")
set(LibOSRM_LDFLAGS "${OSRM_LDFLAGS}")
if(BUILD_AS_SUBPROJECT)
set(LibOSRM_CXXFLAGS "${LibOSRM_CXXFLAGS}" PARENT_SCOPE)
set(LibOSRM_INCLUDE_DIR "${CMAKE_CURRENT_SOURCE_DIR}/include" PARENT_SCOPE)
set(LibOSRM_LIBRARY_DIR "${CMAKE_CURRENT_BINARY_DIR}" PARENT_SCOPE)
set(LibOSRM_LIBRARIES "osrm" PARENT_SCOPE)
set(LibOSRM_DEPENDENT_LIBRARIES "${ENGINE_LIBRARIES}" PARENT_SCOPE)
set(LibOSRM_INCLUDE_DIRS "${CMAKE_CURRENT_SOURCE_DIR}/include"
"${CMAKE_CURRENT_SOURCE_DIR}/include/osrm"
"${CMAKE_CURRENT_SOURCE_DIR}/third_party"
"${DEPENDENCIES_INCLUDE_DIRS}" PARENT_SCOPE)
set(LibOSRM_LIBRARY_DIRS "${LibOSRM_LIBRARY_DIR}" PARENT_SCOPE)
endif()
# pkgconfig defines
set(PKGCONFIG_OSRM_CXXFLAGS "${LibOSRM_CXXFLAGS}")
set(PKGCONFIG_OSRM_LDFLAGS "${LibOSRM_LDFLAGS}")
set(PKGCONFIG_LIBRARY_DIR "${CMAKE_INSTALL_PREFIX}/lib")
set(PKGCONFIG_INCLUDE_DIR "${CMAKE_INSTALL_PREFIX}/include")
list(APPEND DEPENDENCIES_INCLUDE_DIRS "${PKGCONFIG_INCLUDE_DIR}")
list(APPEND DEPENDENCIES_INCLUDE_DIRS "${PKGCONFIG_INCLUDE_DIR}/osrm")
JOIN("-I${DEPENDENCIES_INCLUDE_DIRS}" " -I" PKGCONFIG_OSRM_INCLUDE_FLAGS)
JOIN("${ENGINE_LIBRARIES}" " " PKGCONFIG_OSRM_DEPENDENT_LIBRARIES)
# Set up variables, then write to pkgconfig file
JOIN("${OSRM_DEFINES}" " " OSRM_DEFINES_STRING)
JOIN("-I${OSRM_INCLUDE_PATHS}" " -I" OSRM_INCLUDE_PATHS_STRING)
configure_file(${CMAKE_CURRENT_SOURCE_DIR}/cmake/pkgconfig.in libosrm.pc @ONLY)
install(FILES ${PROJECT_BINARY_DIR}/libosrm.pc DESTINATION lib/pkgconfig)
@@ -729,7 +660,6 @@ if (ENABLE_FUZZING)
set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -fsanitize-coverage=edge,indirect-calls,8bit-counters -fsanitize=address")
set(CMAKE_EXE_LINKER_FLAGS "${CMAKE_EXE_LINKER_FLAGS} -fsanitize=address")
set(OSRM_LDFLAGS "${OSRM_LDFLAGS} -fsanitize=address")
message(STATUS "Using -fsanitize=${FUZZ_SANITIZER} for Fuzz testing")
+1 -1
View File
@@ -4,7 +4,7 @@ set(INFILE ${SOURCE_DIR}/include/util/fingerprint_impl.hpp.in)
file(MD5 ${SOURCE_DIR}/src/tools/contract.cpp MD5PREPARE)
file(MD5 ${SOURCE_DIR}/include/util/static_rtree.hpp MD5RTREE)
file(MD5 ${SOURCE_DIR}/include/util/graph_loader.hpp MD5GRAPH)
file(MD5 ${SOURCE_DIR}/src/storage/storage.cpp MD5OBJECTS)
file(MD5 ${SOURCE_DIR}/include/engine/datafacade/internal_datafacade.hpp MD5OBJECTS)
CONFIGURE_FILE(${INFILE} ${NEWFILE})
+6 -6
View File
@@ -1,11 +1,11 @@
prefix=@CMAKE_INSTALL_PREFIX@
includedir=@PKGCONFIG_INCLUDE_DIR@
libdir=@PKGCONFIG_LIBRARY_DIR@
includedir=${prefix}/include
libdir=${prefix}/lib
Name: libOSRM
Description: Project OSRM library
Version: v@OSRM_VERSION@
Version: v@OSRM_VERSION_MAJOR@.@OSRM_VERSION_MINOR@.@OSRM_VERSION_PATCH@
Requires:
Libs: -L${libdir} -losrm @PKGCONFIG_OSRM_LDFLAGS@
Libs.private: @PKGCONFIG_OSRM_DEPENDENT_LIBRARIES@
Cflags: @PKGCONFIG_OSRM_INCLUDE_FLAGS@ @PKGCONFIG_OSRM_CXXFLAGS@
Libs: -L${libdir} -losrm
Libs.private: @ENGINE_LIBRARY_LISTING@
Cflags: -I${includedir} -I${includedir}/osrm @OSRM_INCLUDE_PATHS_STRING@ @OSRM_DEFINES_STRING@ @CMAKE_CXX_FLAGS@
+281 -336
View File
@@ -1,43 +1,50 @@
## General options
## Environent Variables
All OSRM HTTP requests use a common structure.
### SIGNAL_PARENT_WHEN_READY
The following syntax applies to all services, except as noted.
If the SIGNAL_PARENT_WHEN_READY environment variable is set osrm-routed will
send the USR1 signal to its parent when it will be running and waiting for
requests. This could be used to upgrade osrm-routed to a new binary on the fly
without any service downtime - no incoming requests will be lost.
### Requests
### DISABLE_ACCESS_LOGGING
```endpoint
GET /{service}/{version}/{profile}/{coordinates}[.{format}]?option=value&option=value
If the DISABLE_ACCESS_LOGGING environment variable is set osrm-routed will
**not** log any http requests to standard output. This can be useful in high
traffic setup.
## HTTP API
`osrm-routed` supports only `GET` requests of the form. If you your response size
exceeds the limits of a simple URL encoding, consider using our [NodeJS bindings](https://github.com/Project-OSRM/node-osrm)
or using the [C++ library directly](libosrm.md).
### Request
```
http://{server}/{service}/{version}/{profile}/{coordinates}[.{format}]?option=value&option=value
```
| Parameter | Description |
| --- | --- |
| `service` | One of the following values: [`route`](#route-service), [`nearest`](#nearest-service), [`table`](#table-service), [`match`](#match-service), [`trip`](#trip-service), [`tile`](#tile-service) |
| `version` | Version of the protocol implemented by the service. `v1` for all OSRM 5.x installations |
| `profile` | Mode of transportation, is determined statically by the Lua profile that is used to prepare the data using `osrm-extract`. Typically `car`, `bike` or `foot` if using one of the supplied profiles. |
| `coordinates`| String of format `{longitude},{latitude};{longitude},{latitude}[;{longitude},{latitude} ...]` or `polyline({polyline})`. |
| `format`| Only `json` is supported at the moment. This parameter is optional and defaults to `json`. |
Passing any `option=value` is optional. `polyline` follows Google's polyline format with precision 5 by default and can be generated using [this package](https://www.npmjs.com/package/polyline).
- `server`: location of the server. Example: `127.0.0.1:5000` (default)
- `service`: Name of the service to be used. Support are the following services:
| Service | Description |
|-------------|-----------------------------------------------------------|
| [`route`](#service-route) | fastest path between given coordinates |
| [`nearest`](#service-nearest) | returns the nearest street segment for a given coordinate |
| [`table`](#service-table) | computes distance tables for given coordinates |
| [`match`](#service-match) | matches given coordinates to the road network |
| [`trip`](#service-trip) | Compute the fastest round trip between given coordinates |
| [`tile`](#service-tile) | Return vector tiles containing debugging info |
- `version`: Version of the protocol implemented by the service.
- `profile`: Mode of transportation, is determined statically by the Lua profile that is used to prepare the data using `osrm-extract`.
- `coordinates`: String of format `{longitude},{latitude};{longitude},{latitude}[;{longitude},{latitude} ...]` or `polyline({polyline})`.
- `format`: Only `json` is supported at the moment. This parameter is optional and defaults to `json`.
Passing any `option=value` is optional. `polyline` follows Google's polyline format with precision 5 and can be generated using [this package](https://www.npmjs.com/package/polyline).
To pass parameters to each location some options support an array like encoding:
**Request options**
| Option | Values | Description |
|------------|--------------------------------------------------------|-------------------------------------------------------------------------------------------------------|
|bearings |`{bearing};{bearing}[;{bearing} ...]` |Limits the search to segments with given bearing in degrees towards true north in clockwise direction. |
|radiuses |`{radius};{radius}[;{radius} ...]` |Limits the search to given radius in meters. |
|hints |`{hint};{hint}[;{hint} ...]` |Hint from previous request to derive position in street network. |
Where the elements follow the following format:
| Element | Values |
|------------|--------------------------------------------------------|
|bearing |`{value},{range}` `integer 0 .. 360,integer 0 .. 180` |
|radius |`double >= 0` or `unlimited` (default) |
|hint |Base64 `string` |
```
{option}={element};{element}[;{element} ... ]
```
@@ -50,19 +57,48 @@ Example: 2nd location use the default value for `option`:
{option}={element};;{element}
```
#### Example Requests
## General options
```curl
# Query on Berlin with three coordinates:
curl 'http://router.project-osrm.org/route/v1/driving/13.388860,52.517037;13.397634,52.529407;13.428555,52.523219?overview=false'
# Using polyline:
curl 'http://router.project-osrm.org/route/v1/driving/polyline(ofp_Ik_vpAilAyu@te@g`E)?overview=false'
| Option | Values | Description |
|------------|--------------------------------------------------------|--------------------------------------------------|
|bearings |`{bearing};{bearing}[;{bearing} ...]` |Limits the search to segments with given bearing in degrees towards true north in clockwise direction. |
|radiuses |`{radius};{radius}[;{radius} ...]` |Limits the search to given radius in meters. |
|hints |`{hint};{hint}[;{hint} ...]` |Hint to derive position in street network. |
Where the elements follow the following format:
| Element | Values |
|------------|--------------------------------------------------------|
|bearing |`{value},{range}` `integer 0 .. 360,integer 0 .. 180` |
|radius |`double >= 0` or `unlimited` (default) |
|hint |Base64 `string` |
#### Examples
Query on Berlin with three coordinates:
```
http://router.project-osrm.org/route/v1/driving/13.388860,52.517037;13.397634,52.529407;13.428555,52.523219?overview=false
```
### Responses
Using polyline:
Every response object has a `code` field containing one of the strings below or a service dependent code:
```
http://router.project-osrm.org/route/v1/driving/polyline(ofp_Ik_vpAilAyu@te@g`E)?overview=false
```
### Response
Every response object has a `code` field.
```json
{
"code": {code},
"message": {message}
}
```
Where `code` is on one of the strings below or service dependent:
| Type | Description |
|-------------------|----------------------------------------------------------------------------------|
@@ -76,27 +112,18 @@ Every response object has a `code` field containing one of the strings below or
| `NoSegment` | One of the supplied input coordinates could not snap to street segment. |
| `TooBig` | The request size violates one of the service specific request size restrictions. |
- `message` is a **optional** human-readable error message. All other status types are service dependent.
- In case of an error the HTTP status code will be `400`. Otherwise the HTTP status code will be `200` and `code` will be `Ok`.
`message` is a **optional** human-readable error message. All other status types are service dependent.
#### Example response
In case of an error the HTTP status code will be `400`. Otherwise the HTTP status code will be `200` and `code` will be `Ok`.
## Service `nearest`
Snaps a coordinate to the street network and returns the nearest n matches.
### Request
```json
{
"code": "Ok",
"message": "Everything worked"
}
```
## Services
### Nearest service
Snaps a coordinate to the street network and returns the nearest `n` matches.
```endpoint
GET http://{server}/nearest/v1/{profile}/{coordinates}.json?number={number}
http://{server}/nearest/v1/{profile}/{coordinates}.json?number={number}
```
Where `coordinates` only supports a single `{longitude},{latitude}` entry.
@@ -107,62 +134,26 @@ In addition to the [general options](#general-options) the following options are
|------------|------------------------------|----------------------------------------------------|
|number |`integer >= 1` (default `1`) |Number of nearest segments that should be returned. |
**Response**
### Response
- `code` if the request was successful `Ok` otherwise see the service dependent and general status codes.
- `waypoints` array of `Waypoint` objects sorted by distance to the input coordinate. Each object has at least the following additional properties:
- `distance`: Distance in meters to the supplied input coordinate.
#### Example Requests
### Examples
```curl
# Querying nearest three snapped locations of `13.388860,52.517037` with a bearing between `20° - 340°`.
curl 'http://router.project-osrm.org/nearest/v1/driving/13.388860,52.517037?number=3&bearings=0,20'
Querying nearest three snapped locations of `13.388860,52.517037` with a bearing between `20° - 340°`.
```
http://router.project-osrm.org/nearest/v1/driving/13.388860,52.517037?number=3&bearings=0,20
```
#### Example Response
## Service `route`
### Request
```json
{
"waypoints" : [
{
"hint" : "KSoKADRYroqUBAEAEAAAABkAAAAGAAAAAAAAABhnCQCLtwAA_0vMAKlYIQM8TMwArVghAwEAAQH1a66g",
"distance" : 4.152629,
"name" : "Friedrichstraße",
"location" : [
13.388799,
52.517033
]
},
{
"hint" : "KSoKADRYroqUBAEABgAAAAAAAAAAAAAAKQAAABhnCQCLtwAA7kvMAAxZIQM8TMwArVghAwAAAQH1a66g",
"distance" : 11.811961,
"name" : "Friedrichstraße",
"location" : [
13.388782,
52.517132
]
},
{
"hint" : "KioKgDbbDgCUBAEAAAAAABoAAAAAAAAAPAAAABlnCQCLtwAA50vMADJZIQM8TMwArVghAwAAAQH1a66g",
"distance" : 15.872438,
"name" : "Friedrichstraße",
"location" : [
13.388775,
52.51717
],
}
],
"code" : "Ok"
}
```
### Route service
Finds the fastest route between coordinates in the supplied order.
```endpoint
GET /route/v1/{profile}/{coordinates}?alternatives={true|false}&steps={true|false}&geometries={polyline|polyline6|geojson}&overview={full|simplified|false}&annotations={true|false}
http://{server}/route/v1/{profile}/{coordinates}?alternatives={true|false}&steps={true|false}&geometries={polyline|polyline6|geojson}&overview={full|simplified|false}&annotations={true|false}
```
In addition to the [general options](#general-options) the following options are supported for this service:
@@ -174,11 +165,11 @@ In addition to the [general options](#general-options) the following options are
|annotations |`true`, `false` (default) |Returns additional metadata for each coordinate along the route geometry. |
|geometries |`polyline` (default), `polyline6`, `geojson` |Returned route geometry format (influences overview and per step) |
|overview |`simplified` (default), `full`, `false` |Add overview geometry either full, simplified according to highest zoom level it could be display on, or not at all.|
|continue\_straight |`default` (default), `true`, `false` |Forces the route to keep going straight at waypoints constraining uturns there even if it would be faster. Default value depends on the profile. |
|continue_straight |`default` (default), `true`, `false` |Forces the route to keep going straight at waypoints and don't do a uturn even if it would be faster. Default value depends on the profile. |
\* Please note that even if an alternative route is requested, a result cannot be guaranteed.
**Response**
### Response
- `code` if the request was successful `Ok` otherwise see the service dependent and general status codes.
- `waypoints`: Array of `Waypoint` objects representing all waypoints in order:
@@ -192,22 +183,23 @@ In case of error the following `code`s are supported in addition to the general
All other fields might be undefined.
#### Example Request
### Example
```curl
# Query on Berlin with three coordinates and no overview geometry returned:
curl 'http://router.project-osrm.org/route/v1/driving/13.388860,52.517037;13.397634,52.529407;13.428555,52.523219?overview=false'
Query on Berlin with three coordinates and no overview geometry returned:
```
http://router.project-osrm.org/route/v1/driving/13.388860,52.517037;13.397634,52.529407;13.428555,52.523219?overview=false
```
### Table service
Computes the duration of the fastest route between all pairs of supplied coordinates.
```endpoint
GET /table/v1/{profile}/{coordinates}?{sources}=[{elem}...];&destinations=[{elem}...]
## Service `table`
### Request
```
http://{server}/table/v1/{profile}/{coordinates}?{sources}=[{elem}...];&destinations=[{elem}...]`
```
**Coordinates**
This computes duration tables for the given locations. Allows for both symmetric and asymmetric tables.
### Coordinates
In addition to the [general options](#general-options) the following options are supported for this service:
@@ -219,7 +211,7 @@ In addition to the [general options](#general-options) the following options are
Unlike other array encoded options, the length of `sources` and `destinations` can be **smaller or equal**
to number of input locations;
**Example:**
Example:
```
sources=0;5;7&destinations=5;1;4;2;3;6
@@ -229,20 +221,7 @@ sources=0;5;7&destinations=5;1;4;2;3;6
|------------|-----------------------------|
|index |`0 <= integer < #locations` |
#### Example Request
```curl
# Returns a 3x3 matrix:
curl 'http://router.project-osrm.org/table/v1/driving/13.388860,52.517037;13.397634,52.529407;13.428555,52.523219'
# Returns a 1x3 matrix
curl 'http://router.project-osrm.org/table/v1/driving/13.388860,52.517037;13.397634,52.529407;13.428555,52.523219?sources=0'
# Returns a asymmetric 3x2 matrix with from the polyline encoded locations `qikdcB}~dpXkkHz`:
curl 'http://router.project-osrm.org/table/v1/driving/polyline(egs_Iq_aqAppHzbHulFzeMe`EuvKpnCglA)?sources=0;1;3&destinations=2;4'
```
**Response**
### Response
- `code` if the request was successful `Ok` otherwise see the service dependent and general status codes.
- `durations` array of arrays that stores the matrix in row-major order. `durations[i][j]` gives the travel time from
@@ -258,39 +237,53 @@ In case of error the following `code`s are supported in addition to the general
All other fields might be undefined.
### Match service
#### Examples
Map matching matches/snaps given GPS points to the road network in the most plausible way.
Please note the request might result multiple sub-traces. Large jumps in the timestamps (> 60s) or improbable transitions lead to trace splits if a complete matching could not be found.
Returns a `3x3` matrix:
```
http://router.project-osrm.org/table/v1/driving/13.388860,52.517037;13.397634,52.529407;13.428555,52.523219
```
Returns a `1x3` matrix:
```
http://router.project-osrm.org/table/v1/driving/13.388860,52.517037;13.397634,52.529407;13.428555,52.523219?sources=0
```
Returns a asymmetric 3x2 matrix with from the polyline encoded locations `qikdcB}~dpXkkHz`:
```
http://router.project-osrm.org/table/v1/driving/polyline(egs_Iq_aqAppHzbHulFzeMe`EuvKpnCglA)?sources=0;1;3&destinations=2;4
```
## Service `match`
Map matching matches given GPS points to the road network in the most plausible way.
Please note the request might result multiple sub-traces. Large jumps in the timestamps (>60s) or improbable transitions lead to trace splits if a complete matching could not be found.
The algorithm might not be able to match all points. Outliers are removed if they can not be matched successfully.
```endpoint
GET /match/v1/{profile}/{coordinates}?steps={true|false}&geometries={polyline|polyline6|geojson}&overview={simplified|full|false}&annotations={true|false}
### Request
```
http://{server}/match/v1/{profile}/{coordinates}?steps={true|false}&geometries={polyline|polyline6|geojson}&overview={simplified|full|false}&annotations={true|false}
```
In addition to the [general options](#general-options) the following options are supported for this service:
|Option |Values |Description |
|------------|------------------------------------------------|------------------------------------------------------------------------------------------|
|steps |`true`, `false` (default) |Return route steps for each route |
|geometries |`polyline` (default), `polyline6`, `geojson` |Returned route geometry format (influences overview and per step) |
|annotations |`true`, `false` (default) |Returns additional metadata for each coordinate along the route geometry. |
|overview |`simplified` (default), `full`, `false` |Add overview geometry either full, simplified according to highest zoom level it could be display on, or not at all.|
|timestamps |`{timestamp};{timestamp}[;{timestamp} ...]` |Timestamps for the input locations in seconds since UNIX epoch. Timestamps need to be monotonically increasing. |
|timestamps |`{timestamp};{timestamp}[;{timestamp} ...]` |Timestamp of the input location. Timestamps need to be monotonically increasing. |
|radiuses |`{radius};{radius}[;{radius} ...]` |Standard deviation of GPS precision used for map matching. If applicable use GPS accuracy.|
|Parameter |Values |
|------------|-----------------------------------|
|timestamp |`integer` seconds since UNIX epoch |
|radius |`double >= 0` (default 5m) |
The radius for each point should be the standard error of the location measured in meters from the true location.
Use `Location.getAccuracy()` on Android or `CLLocation.horizontalAccuracy` on iOS.
This value is used to determine which points should be considered as candidates (larger radius means more candidates) and how likely each candidate is (larger radius means far-away candidates are penalized less).
The area to search is chosen such that the correct candidate should be considered 99.9% of the time (for more details see [this ticket](https://github.com/Project-OSRM/osrm-backend/pull/3184)).
**Response**
|Parameter |Values |
|------------|------------------------------|
|timestamp |`integer` UNIX-like timestamp |
|radius |`double >= 0` (default 5m) |
### Response
- `code` if the request was successful `Ok` otherwise see the service dependent and general status codes.
- `tracepoints`: Array of `Waypoint` objects representing all points of the trace in order.
If the trace point was ommited by map matching because it is an outlier, the entry will be `null`.
@@ -308,15 +301,17 @@ In case of error the following `code`s are supported in addition to the general
All other fields might be undefined.
### Trip service
## Service `trip`
The trip plugin solves the Traveling Salesman Problem using a greedy heuristic (farthest-insertion algorithm).
The returned path does not have to be the fastest path, as TSP is NP-hard it is only an approximation.
Note that if the input coordinates can not be joined by a single trip (e.g. the coordinates are on several disconnected islands)
multiple trips for each connected component are returned.
```endpoint
GET /trip/v1/{profile}/{coordinates}?steps={true|false}&geometries={polyline|polyline6|geojson}&overview={simplified|full|false}&annotations={true|false}'
### Request
```
http://{server}/trip/v1/{profile}/{coordinates}?steps={true|false}&geometries={polyline|polyline6|geojson}&overview={simplified|full|false}&annotations={true|false}
```
In addition to the [general options](#general-options) the following options are supported for this service:
@@ -328,7 +323,7 @@ In addition to the [general options](#general-options) the following options are
|geometries |`polyline` (default), `polyline6`, `geojson` |Returned route geometry format (influences overview and per step) |
|overview |`simplified` (default), `full`, `false` |Add overview geometry either full, simplified according to highest zoom level it could be display on, or not at all.|
**Response**
### Response
- `code` if the request was successful `Ok` otherwise see the service dependent and general status codes.
- `waypoints`: Array of `Waypoint` objects representing all waypoints in input order. Each `Waypoint` object has the following additional properties:
@@ -344,68 +339,23 @@ In case of error the following `code`s are supported in addition to the general
All other fields might be undefined.
### Tile service
This service generates [Mapbox Vector Tiles](https://www.mapbox.com/developers/vector-tiles/) that can be viewed with a vector-tile capable slippy-map viewer. The tiles contain road geometries and metadata that can be used to examine the routing graph. The tiles are generated directly from the data in-memory, so are in sync with actual routing results, and let you examine which roads are actually routable, and what weights they have applied.
```endpoint
GET /tile/v1/{profile}/tile({x},{y},{zoom}).mvt
```
The `x`, `y`, and `zoom` values are the same as described at https://wiki.openstreetmap.org/wiki/Slippy_map_tilenames, and are supported by vector tile viewers like [Mapbox GL JS](https://www.mapbox.com/mapbox-gl-js/api/).
#### Example request
```curl
# This fetches a Z=13 tile for downtown San Francisco:
curl 'http://router.project-osrm.org/tile/v1/car/tile(1310,3166,13).mvt'
```
#### Example response
> ![example rendered tile](images/example-tile-response.png)
> http://map.project-osrm.org/debug/#14.33/52.5212/13.3919
The response object is either a binary encoded blob with a `Content-Type` of `application/x-protobuf`, or a `404` error. Note that OSRM is hard-coded to only return tiles from zoom level 12 and higher (to avoid accidentally returning extremely large vector tiles).
Vector tiles contain two layers:
`speeds` layer:
| Field | Type | Description |
| ------------ | --------- | ---------------------------------------- |
| `speed` | `integer` | the speed on that road segment, in km/h |
| `is_small` | `boolean` | whether this segment belongs to a small (< 1000 node) [strongly connected component](https://en.wikipedia.org/wiki/Strongly_connected_component) |
| `datasource` | `string` | the source for the speed value (normally `lua profile` unless you're using the [traffic update feature](https://github.com/Project-OSRM/osrm-backend/wiki/Traffic), in which case it contains the stem of the filename that supplied the speed value for this segment |
| `duration` | `float` | how long this segment takes to traverse, in seconds |
| `name` | `string` | the name of the road this segment belongs to |
`turns` layer:
| Field | Type | Description |
| ------------ | --------- | ---------------------------------------- |
| `bearing_in` | `integer` | the absolute bearing that approaches the intersection. -180 to +180, 0 = North, 90 = East |
| `turn_angle` | `integer` | the angle of the turn, relative to the `bearing_in`. -180 to +180, 0 = straight ahead, 90 = 90-degrees to the right |
| `cost` | `float` | the time we think it takes to make that turn, in seconds. May be negative, depending on how the data model is constructed (some turns get a "bonus"). |
## Result objects
### Route object
### Route
Represents a route through (potentially multiple) waypoints.
**Properties**
#### Properties
- `distance`: The distance traveled by the route, in `float` meters.
- `duration`: The estimated travel time, in `float` number of seconds.
- `geometry`: The whole geometry of the route value depending on `overview` parameter, format depending on the `geometries` parameter. See `RouteStep`'s `geometry` field for a parameter documentation.
| overview | Description |
|------------|-----------------------------|
| simplified | Geometry is simplified according to the highest zoom level it can still be displayed on full. |
| full | Geometry is not simplified. |
| false | Geometry is not added. |
| overview | Description |
|------------|-----------------------------|
| simplified | Geometry is simplified according to the highest zoom level it can still be displayed on full. |
| full | Geometry is not simplified. |
| false | Geometry is not added. |
- `legs`: The legs between the given waypoints, an array of `RouteLeg` objects.
@@ -433,34 +383,34 @@ Three input coordinates, `geometry=geojson`, `steps=false`:
}
```
### RouteLeg object
### RouteLeg
Represents a route between two waypoints.
**Properties**
#### Properties
- `distance`: The distance traveled by this route leg, in `float` meters.
- `duration`: The estimated travel time, in `float` number of seconds.
- `summary`: Summary of the route taken as `string`. Depends on the `steps` parameter:
| steps | |
|--------------|-----------------------------------------------------------------------|
| true | Names of the two major roads used. Can be empty if route is too short.|
| false | empty `string` |
| steps | |
|--------------|-----------------------------------------------------------------------|
| true | Names of the two major roads used. Can be empty if route is too short.|
| false | empty `string` |
- `steps`: Depends on the `steps` parameter.
| steps | |
|--------------|-----------------------------------------------------------------------|
| true | array of `RouteStep` objects describing the turn-by-turn instructions |
| false | empty array |
| steps | |
|--------------|-----------------------------------------------------------------------|
| true | array of `RouteStep` objects describing the turn-by-turn instructions |
| false | empty array |
- `annotation`: Additional details about each coordinate along the route geometry:
| annotations | |
|--------------|-----------------------------------------------------------------------|
| true | An `Annotation` object containing node ids, durations and distances |
| false | `undefined` |
| annotations | |
|--------------|-----------------------------------------------------------------------|
| true | An `Annotation` object containing node ids, durations and distances |
| false | `undefined` |
#### Example
@@ -480,11 +430,11 @@ With `steps=false` and `annotations=true`:
}
```
### Annotation object
### Annotation
Annotation of the whole route leg with fine-grained information about each segment or node id.
**Properties**
#### Properties
- `distance`: The distance, in metres, between each pair of coordinates
- `duration`: The duration between each pair of coordinates, in seconds
@@ -503,24 +453,24 @@ Annotation of the whole route leg with fine-grained information about each segme
```
### RouteStep object
### RouteStep
A step consists of a maneuver such as a turn or merge, followed
by a distance of travel along a single way to the subsequent
step.
**Properties**
#### Properties
- `distance`: The distance of travel from the maneuver to the subsequent step, in `float` meters.
- `duration`: The estimated travel time, in `float` number of seconds.
- `geometry`: The unsimplified geometry of the route segment, depending on the `geometries` parameter.
| `geometry` | |
|------------|--------------------------------------------------------------------|
| polyline | [polyline](https://www.npmjs.com/package/polyline) with precision 5 in [latitude,longitude] encoding |
| polyline6 | [polyline](https://www.npmjs.com/package/polyline) with precision 6 in [latitude,longitude] encoding |
| geojson | [GeoJSON `LineString`](http://geojson.org/geojson-spec.html#linestring) |
| geometries | |
|------------|--------------------------------------------------------------------|
| polyline | [polyline](https://www.npmjs.com/package/polyline) with precision 5 in [latitude,longitude] encoding |
| polyline6 | [polyline](https://www.npmjs.com/package/polyline) with precision 6 in [latitude,longitude] encoding |
| geojson | [GeoJSON `LineString`](http://geojson.org/geojson-spec.html#linestring) or [GeoJSON `Point`](http://geojson.org/geojson-spec.html#point) if it is only one coordinate (not wrapped by a GeoJSON feature)|
- `name`: The name of the way along which travel proceeds.
- `ref`: A reference number or code for the way. Optionally included, if ref data is available for the given way.
- `pronunciation`: The pronunciation hint of the way name. Will be `undefined` if there is no pronunciation hit.
@@ -531,49 +481,42 @@ step.
#### Example
```json
```
{
"geometry" : "{lu_IypwpAVrAvAdI",
"mode" : "driving",
"duration" : 15.6,
"intersections" : [
{ "bearings" : [ 10, 92, 184, 270 ],
"lanes" : [
{ "indications" : [ "left", "straight" ],
"valid" : "false" },
{ "valid" : "true",
"indications" : [ "right" ] }
],
"out" : 2,
"in" : 3,
"entry" : [ "true", "true", "true", "false" ],
"location" : [ 13.39677, 52.54366 ]
},
{ "out" : 1,
"lanes" : [
{ "indications" : [ "straight" ],
"valid" : "true" },
{ "indications" : [ "right" ],
"valid" : "false" }
],
"bearings" : [ 60, 240, 330 ],
"in" : 0,
"entry" : [ "false", "true", "true" ],
"location" : [ 13.394718, 52.543096 ]
}
],
"name" : "Lortzingstraße",
"distance" : 152.3,
"maneuver" : {
"modifier" : "right",
"type" : "turn"
}
}
"distance":152.3,
"duration":15.6,
"name":"Lortzingstraße",
"maneuver":{
"type":"turn",
"modifier":"right",
},
"geometry":"{lu_IypwpAVrAvAdI",
"mode":"driving",
"intersections":[
{"location":[13.39677,52.54366],
"in":3,
"out":2,
"bearings":[10,92,184,270],
"entry":["true","true","true","false"],
"lanes":[
{"indications":["left","straight"], "valid":"false"},
{"indications":["right"], "valid":"true"}
]},
{"location":[13.394718,52.543096],
"in":0,
"out":1,
"bearings":[60,240,330],
"entry":["false","true","true"]
"lanes":[
{"indications":["straight"], "valid":"true"},
{"indications":["right"], "valid":"false"}
]}
]}
```
### StepManeuver object
### StepManeuver
**Properties**
#### Properties
- `location`: A `[longitude, latitude]` pair describing the location of the turn.
- `bearing_before`: The clockwise angle from true north to the
@@ -583,79 +526,79 @@ step.
- `type` A string indicating the type of maneuver. **new identifiers might be introduced without API change**
Types unknown to the client should be handled like the `turn` type, the existance of correct `modifier` values is guranteed.
| `type` | Description |
|------------------|--------------------------------------------------------------|
| `turn` | a basic turn into direction of the `modifier` |
| `new name` | no turn is taken/possible, but the road name changes. The road can take a turn itself, following `modifier`. |
| `depart` | indicates the departure of the leg |
| `arrive` | indicates the destination of the leg |
| `merge` | merge onto a street (e.g. getting on the highway from a ramp, the `modifier specifies the direction of the merge`) |
| `ramp` | **Deprecated**. Replaced by `on_ramp` and `off_ramp`. |
| `on ramp` | take a ramp to enter a highway (direction given my `modifier`) |
| `off ramp` | take a ramp to exit a highway (direction given my `modifier`) |
| `fork` | take the left/right side at a fork depending on `modifier` |
| `end of road` | road ends in a T intersection turn in direction of `modifier`|
| `use lane` | going straight on a specific lane |
| `continue` | Turn in direction of `modifier` to stay on the same road |
| `roundabout` | traverse roundabout, has additional field `exit` with NR if the roundabout is left. `the modifier specifies the direction of entering the roundabout` |
| `rotary` | a traffic circle. While very similar to a larger version of a roundabout, it does not necessarily follow roundabout rules for right of way. It can offer `rotary_name/rotary_pronunciation` in addition to the `exit` parameter. |
| `roundabout turn`| Describes a turn at a small roundabout that should be treated as normal turn. The `modifier` indicates the turn direciton. Example instruction: `At the roundabout turn left`. |
| `notification` | not an actual turn but a change in the driving conditions. For example the travel mode. If the road takes a turn itself, the `modifier` describes the direction |
| `type` | Description |
|------------------|--------------------------------------------------------------|
| `turn` | a basic turn into direction of the `modifier` |
| `new name` | no turn is taken/possible, but the road name changes. The road can take a turn itself, following `modifier`. |
| `depart` | indicates the departure of the leg |
| `arrive` | indicates the destination of the leg |
| `merge` | merge onto a street (e.g. getting on the highway from a ramp, the `modifier specifies the direction of the merge`) |
| `ramp` | **Deprecated**. Replaced by `on_ramp` and `off_ramp`. |
| `on ramp` | take a ramp to enter a highway (direction given my `modifier`) |
| `off ramp` | take a ramp to exit a highway (direction given my `modifier`) |
| `fork` | take the left/right side at a fork depending on `modifier` |
| `end of road` | road ends in a T intersection turn in direction of `modifier`|
| `use lane` | going straight on a specific lane |
| `continue` | Turn in direction of `modifier` to stay on the same road |
| `roundabout` | traverse roundabout, has additional field `exit` with NR if the roundabout is left. `the modifier specifies the direction of entering the roundabout` |
| `rotary` | a larger version of a roundabout, can offer `rotary_name/rotary_pronunciation` in addition to the `exit` parameter. |
| `roundabout turn`| Describes a turn at a small roundabout that should be treated as normal turn. The `modifier` indicates the turn direciton. Example instruction: `At the roundabout turn left`. |
| `notification` | not an actual turn but a change in the driving conditions. For example the travel mode. If the road takes a turn itself, the `modifier` describes the direction |
Please note that even though there are `new name` and `notification` instructions, the `mode` and `name` can change
between all instructions. They only offer a fallback in case nothing else is to report.
- `modifier` An optional `string` indicating the direction change of the maneuver.
| `modifier` | Description |
|-------------------|-------------------------------------------|
| `uturn` | indicates reversal of direction |
| `sharp right` | a sharp right turn |
| `right` | a normal turn to the right |
| `slight right` | a slight turn to the right |
| `straight` | no relevant change in direction |
| `slight left` | a slight turn to the left |
| `left` | a normal turn to the left |
| `sharp left` | a sharp turn to the left |
| `modifier` | Description |
|-------------------|-------------------------------------------|
| `uturn` | indicates reversal of direction |
| `sharp right` | a sharp right turn |
| `right` | a normal turn to the right |
| `slight right` | a slight turn to the right |
| `straight` | no relevant change in direction |
| `slight left` | a slight turn to the left |
| `left` | a normal turn to the left |
| `sharp left` | a sharp turn to the left |
The list of turns without a modifier is limited to: `depart/arrive`. If the source/target location is close enough to the `depart/arrive` location, no modifier will be given.
The meaning depends on the `type` field.
| `type` | Description |
|------------------------|---------------------------------------------------------------------------------------------------------------------------|
| `turn` | `modifier` indicates the change in direction accomplished through the turn |
| `depart`/`arrive` | `modifier` indicates the position of departure point and arrival point in relation to the current direction of travel |
| `type` | Description |
|------------------------|---------------------------------------------------------------------------------------------------------------------------|
| `turn` | `modifier` indicates the change in direction accomplished through the turn |
| `depart`/`arrive` | `modifier` indicates the position of departure point and arrival point in relation to the current direction of travel |
- `exit` An optional `integer` indicating number of the exit to take. The field exists for the following `type` field:
| `type` | Description |
|------------------------|---------------------------------------------------------------------------------------------------------------------------|
| `roundabout`/`rotary` | Number of the roundabout exit to take. If exit is `undefined` the destination is on the roundabout. |
| else | Indicates the number of intersections passed until the turn. Example instruction: `at the fourth intersection, turn left` |
| `type` | Description |
|------------------------|---------------------------------------------------------------------------------------------------------------------------|
| `roundabout`/`rotary` | Number of the roundabout exit to take. If exit is `undefined` the destination is on the roundabout. |
| else | Indicates the number of intersections passed until the turn. Example instruction: `at the fourth intersection, turn left` |
New properties (potentially depending on `type`) may be introduced in the future without an API version change.
### Lane object
### Lane
A `Lane` represents a turn lane at the corresponding turn location.
**Properties**
#### Properties
- `indications`: a indication (e.g. marking on the road) specifying the turn lane. A road can have multiple indications (e.g. an arrow pointing straight and left). The indications are given in an array, each containing one of the following types. Further indications might be added on without an API version change.
| `value` | Description |
|------------------------|---------------------------------------------------------------------------------------------------------------------------|
| `none` | No dedicated indication is shown. |
| `uturn` | An indication signaling the possibility to reverse (i.e. fully bend arrow). |
| `sharp right` | An indication indicating a sharp right turn (i.e. strongly bend arrow). |
| `right` | An indication indicating a right turn (i.e. bend arrow). |
| `slight right` | An indication indicating a slight right turn (i.e. slightly bend arrow). |
| `straight` | No dedicated indication is shown (i.e. straight arrow). |
| `slight left` | An indication indicating a slight left turn (i.e. slightly bend arrow). |
| `left` | An indication indicating a left turn (i.e. bend arrow). |
| `sharp left` | An indication indicating a sharp left turn (i.e. strongly bend arrow). |
| `value` | Description |
|------------------------|---------------------------------------------------------------------------------------------------------------------------|
| `none` | No dedicated indication is shown. |
| `uturn` | An indication signaling the possibility to reverse (i.e. fully bend arrow). |
| `sharp right` | An indication indicating a sharp right turn (i.e. strongly bend arrow). |
| `right` | An indication indicating a right turn (i.e. bend arrow). |
| `slight right` | An indication indicating a slight right turn (i.e. slightly bend arrow). |
| `straight` | No dedicated indication is shown (i.e. straight arrow). |
| `slight left` | An indication indicating a slight left turn (i.e. slightly bend arrow). |
| `left` | An indication indicating a left turn (i.e. bend arrow). |
| `sharp left` | An indication indicating a sharp left turn (i.e. strongly bend arrow). |
- `valid`: a boolean flag indicating whether the lane is a valid choice in the current maneuver
@@ -668,12 +611,12 @@ A `Lane` represents a turn lane at the corresponding turn location.
}
```
### Intersection object
### Intersection
An intersection gives a full representation of any cross-way the path passes bay. For every step, the very first intersection (`intersections[0]`) corresponds to the
location of the StepManeuver. Further intersections are listed for every cross-way until the next turn instruction.
**Properties**
#### Properties
- `location`: A `[longitude, latitude]` pair describing the location of the turn.
- `bearings`: A list of bearing values (e.g. [0,90,180,270]) that are available at the intersection. The bearings describe all available roads at the intersection.
@@ -687,8 +630,7 @@ location of the StepManeuver. Further intersections are listed for every cross-w
- `lanes`: Array of `Lane` objects that denote the available turn lanes at the intersection. If no lane information is available for an intersection, the `lanes` property will not be present.
#### Example
```json
```
{
"location":[13.394718,52.543096],
"in":0,
@@ -699,32 +641,35 @@ location of the StepManeuver. Further intersections are listed for every cross-w
"indications": ["left", "straight"],
"valid": "false"
}
]}
}
```
### Waypoint object
### Waypoint
Object used to describe waypoint on a route.
**Properties**
#### Properties
- `name` Name of the street the coordinate snapped to
- `location` Array that contains the `[longitude, latitude]` pair of the snapped coordinate
- `distance` The distance of the snapped point from the original
- `hint` Unique internal identifier of the segment (ephemeral, not constant over data updates)
This can be used on subsequent request to significantly speed up the query and to connect multiple services.
E.g. you can use the `hint` value obtained by the `nearest` query as `hint` values for `route` inputs.
#### Example
## Service `tile`
```json
{
"hint" : "KSoKADRYroqUBAEAEAAAABkAAAAGAAAAAAAAABhnCQCLtwAA_0vMAKlYIQM8TMwArVghAwEAAQH1a66g",
"distance" : 4.152629,
"name" : "Friedrichstraße",
"location" : [
13.388799,
52.517033
]
}
This generates [Mapbox Vector Tiles](https://www.mapbox.com/developers/vector-tiles/) that can be viewed with a vector-tile capable slippy-map viewer. The tiles contain road geometries and metadata that can be used to examine the routing graph. The tiles are generated directly from the data in-memory, so are in sync with actual routing results, and let you examine which roads are actually routable, and what weights they have applied.
### Request
```
http://{server}/tile/v1/{profile}/tile({x},{y},{zoom}).mvt
```
The `x`, `y`, and `zoom` values are the same as described at https://wiki.openstreetmap.org/wiki/Slippy_map_tilenames, and are supported by vector tile viewers like [Mapbox GL JS](https://www.mapbox.com/mapbox-gl-js/api/).
### Response
The response object is either a binary encoded blob with a `Content-Type` of `application/x-protobuf`, or a `404` error. Note that OSRM is hard-coded to only return tiles from zoom level 12 and higher (to avoid accidentally returning extremely large vector tiles).
Vector tiles contain just a single layer named `speeds`. Within that layer, features can have `speed` (int) and `is_small` (boolean) attributes.
Binary file not shown.

Before

Width:  |  Height:  |  Size: 694 KiB

+6 -13
View File
@@ -1,11 +1,7 @@
## Introduction
OSRM can be used as a library (libosrm) via C++ instead of using it through the HTTP interface and `osrm-routed`. This allows for fine-tuning OSRM and has much less overhead. Here is a quick introduction into how to use `libosrm` in the upcoming v5 release.
Take a look at the example code that lives in the [example directory](https://github.com/Project-OSRM/osrm-backend/tree/master/example). Here is all you ever wanted to know about `libosrm`, that is a short description of what the types do and where to find documentation on it:
## Important interface objects
- [`EngineConfig`](https://github.com/Project-OSRM/osrm-backend/blob/master/include/engine/engine_config.hpp) - for initializing an OSRM instance we can configure certain properties and constraints. E.g. the storage config is the base path such as `france.osm.osrm` from which we derive and load `france.osm.osrm.*` auxiliary files. This also lets you set constraints such as the maximum number of locations allowed for specific services.
- [`OSRM`](https://github.com/Project-OSRM/osrm-backend/blob/master/include/osrm/osrm.hpp) - this is the main Routing Machine type with functions such as `Route` and `Table`. You initialize it with a `EngineConfig`. It does all the heavy lifting for you. Each function takes its own parameters, e.g. the `Route` function takes `RouteParameters`, and a out-reference to a JSON result that gets filled. The return value is a `Status`, indicating error or success.
@@ -20,14 +16,11 @@ Take a look at the example code that lives in the [example directory](https://gi
- [Parameters for other services](https://github.com/Project-OSRM/osrm-backend/tree/master/include/engine/api) - here are all other `*Parameters` you need for other Routing Machine services.
- [JSON](https://github.com/Project-OSRM/osrm-backend/blob/master/include/util/json_container.hpp) - this is a sum type resembling JSON. The Routing Machine service functions take a out-ref to a JSON result and fill it accordingly. It is currently implemented using [mapbox/variant](https://github.com/mapbox/variant) which is similar to [Boost.Variant](http://www.boost.org/doc/libs/1_55_0/doc/html/variant.html). There are two ways to work with this sum type: either provide a visitor that acts on each type on visitation or use the `get` function in case you're sure about the structure. The JSON structure is written down in the [HTTP API](#http-api).
- [JSON](https://github.com/Project-OSRM/osrm-backend/blob/master/include/util/json_container.hpp) - this is a sum type resembling JSON. The Routing Machine service functions take a out-ref to a JSON result and fill it accordingly. It is currently implemented using [mapbox/variant](https://github.com/mapbox/variant) which is similar to [Boost.Variant](http://www.boost.org/doc/libs/1_55_0/doc/html/variant.html) (Boost documentation is great). There are two ways to work with this sum type: either provide a visitor that acts on each type on visitation or use the `get` function in case you're sure about the structure. The JSON structure is written down in the [[v5 server API|Server-API-v5,-current]].
## Example
------------------------------------------------------------------------------------------------------------------
See [the example folder](https://github.com/Project-OSRM/osrm-backend/tree/master/example) in the OSRM repository.
## Workflow
- Create an `OSRM` instance initialized with a `EngineConfig`
- Call the service function on the `OSRM` object providing service specific `*Parameters`
- Check the return code and use the JSON result
To summarize:
- create an `OSRM` instance initialized with a `EngineConfig`
- call the service function on the `OSRM` object providing service specific `*Parameters`
- check the return code and use the JSON result
-2
View File
@@ -32,7 +32,6 @@ We may introduce forward-compatible changes: query parameters and response prope
- The `master` branch is for the bleeding edge development
- We create and maintain release branches `x.y` to control the release flow
- We create the release branch once we tagged the final version `x.y.0` version, RCs go on master
- No minor or major version will be released without a code-equal release candidates
- For quality assurance, release candidates will be run on the demo server for 24 hours before releaseing the version proper
- Patch versions may be released without a release candidate
@@ -45,7 +44,6 @@ We may introduce forward-compatible changes: query parameters and response prope
3. Make sure `CHANGELOG.md` is up to date.
4. Make sure the OSRM version in `CMakeLists.txt` is up to date
5. Use an annotated tag to mark the release: `git tag vx.y.z -a` Body of the tag description should be the changelog entries.
6. Use `npm run build-api-docs` to generate the API documentation. Copy `build/docs/*` to `https://github.com/Project-OSRM/project-osrm.github.com` in the `docs/vN.N.N/api` directory
6. Push tags and commits: `git push; git push --tags`
8. Proceede with the `node-osrm` release as [outlined in the repository](https://github.com/Project-OSRM/node-osrm/blob/master/docs/releasing.md).
9. If not a release-candidate: Write a mailing-list post to osrm-talk@openstreetmap.org to announce the release
-14
View File
@@ -1,14 +0,0 @@
## Environment Variables
### SIGNAL_PARENT_WHEN_READY
If the SIGNAL_PARENT_WHEN_READY environment variable is set osrm-routed will
send the USR1 signal to its parent when it will be running and waiting for
requests. This could be used to upgrade osrm-routed to a new binary on the fly
without any service downtime - no incoming requests will be lost.
### DISABLE_ACCESS_LOGGING
If the DISABLE_ACCESS_LOGGING environment variable is set osrm-routed will
**not** log any http requests to standard output. This can be useful in high
traffic setup.
-16
View File
@@ -1,16 +0,0 @@
var fs = require('fs');
/**
* This file exports the content of your website, as a bunch of concatenated
* Markdown files. By doing this explicitly, you can control the order
* of content without any level of abstraction.
*
* Using the brfs module, fs.readFileSync calls in this file are translated
* into strings of those files' content before the file is delivered to a
* browser: the content is read ahead-of-time and included in bundle.js.
*/
module.exports =
'# HTTP API\n' +
fs.readFileSync('./content/http.md', 'utf8') + '\n'+
'# libosrm C++ API\n' +
fs.readFileSync('./content/libosrm.md', 'utf8') + '\n';
-16
View File
@@ -1,16 +0,0 @@
<!DOCTYPE html>
<html>
<head>
<meta charset='utf-8' />
<meta http-equiv='X-UA-Compatible' content='IE=11' />
<title>OSRM API Documentation</title>
<meta name='viewport' content='initial-scale=1,maximum-scale=1,user-scalable=no' />
<link href='css/base.css' rel='stylesheet' />
<link href='css/style.css' rel='stylesheet' />
<link href='css/railscasts.css' rel='stylesheet' />
</head>
<body>
<!--START--><div id='app'></div><!--STOP-->
<script src='bundle.js'></script>
</body>
</html>
-63
View File
@@ -1,63 +0,0 @@
'use strict';
/**
* Brand names, in order to decreasing length, for different
* media queries.
*/
module.exports.brandNames = {
desktop: 'OSRM API Documentation',
tablet: 'OSRM API Docs',
mobile: 'OSRM API'
};
/**
* Classes that define the top-left brand box.
*/
module.exports.brandClasses = 'fill-red';
/**
* Text for the link back to the linking website.
*/
module.exports.backLink = 'Back to project-osrm.org';
/**
* Runs after highlighting code samples. You can use this
* hook to, for instance, highlight a token and link it
* to some canonical part of documentation.
*/
module.exports.postHighlight = function(html) {
return html;
};
/**
* Highlight tokens in endpoint URLs, optionally linking to documentation
* or adding detail. This is the equivalent of postHighlight but it
* operates on endpoint URLs only.
*/
function highlightTokens(str) {
return str.replace(/{[\w_]+}/g,
(str) => '<span class="strong">' + str + '</span>');
}
/**
* Transform endpoints given as strings in a highlighted block like
*
* ```endpoint
* GET /foo/bar
* ```
*
* Into HTML nodes that format those endpoints in nice ways.
*/
module.exports.transformURL = function(value) {
let parts = value.split(/\s+/);
return {
type: 'html',
value: `<div class='endpoint dark fill-dark round '>
<div class='round-left pad0y pad1x fill-lighten0 code small endpoint-method'>${parts[0]}</div>
<div class='pad0 code small endpoint-url'>${highlightTokens(parts[1])}</div>
</div>`
};
};
module.exports.remarkPlugins = [];
-78
View File
@@ -309,81 +309,3 @@ And the relations
```
Unless this format is used, OSRM will omit the (then ambiguous) turn restrictions and ignore them.
## My Guidance Tests are Failing - Understanding what you can change
If you change some stuff in guidance, you will easily see tests change their result. E.g. if you change the angles for which we report `right`, then obviously some tests might not report a `direction modifier` named `right` anymore.
This small section will try to guide you in making the correct decisions for changing the behaviour of tests.
The difficulty in guidance tests is that not all items can be translated 1:1 from the ascii art into turn-angles.
The turn-angle calculation tries to find turn angles that would represent perceived turn angles, not the exact angle at the connection.
This is necessary, since connections in OSM are always bound by the paradigm that the way is supposed to be in the middle of the actual road.
For broad streets, you will see stronger angles than the actual turns.
### Don't change the test, change the expected behaviour
If we have a test that looks like this:
```
Given a grid size of 5 m
Given the node map
"""
a - b - - - - - - c
\
d - - - - - e
"""
When I route I should get
| waypoints | route | turns |
| a,e | abc,bde,bde | depart,turn slight right,arrive|
```
And the test reports `turn right` for the route `a->e`, where before it said `slight right`.
If you changed the turn angles, obviously you can expect changes in the distinction between `slight right` and `right`.
In such a case it is, of course, reasonable to change the expected route to report `right` instead of `slight right`. You should consider inspecting the actual turn angles at `b` to see if you feel that change is justified.
However, you should never adjust the test itself.
If you look at a failure, the other way around
```
Given a grid size of 5 m
Given the node map
"""
a - b - - - - - - c
\
d - - - - - e
"""
When I route I should get
| waypoints | route | turns |
| a,e | abc,bde,bde | depart,turn right,arrive|
```
where we see a `slight right`, over the expected `right`.
We could be tempted to adjust the grid size (e.g. from `10 m` to `20` meters).
Such a change would fundamentally alter the tests, though.
Since the part `b-d` is a short offset, when we are looking at a grid of size `5 m`, the angle calculation will try and compensate for this offset.
In this case we would see a very slight turn angle. If your change now reports different turn angles, you can of course change the expected result. But you should not adjust the grid size. The test would be testing turn angles of `180` and `100` degrees, instead of `180` and `160`.
### Consider Post-Processing Impacts
Some changes you might see could look completely unrelated. To understand the impact of your changes, you can make use of the debugging utilities you can finde in `util/debug.hpp` (and potentially other related headers).
If your test is inspecting a series of turns (remember, a turn not necessarily equals an instruction), you could see interaction with post-processing.
To see the unprocessed turns, you should print the steps at the end of step assembly (`assembleSteps` in `engine/guidance/assemble_steps.hpp`).
If you see unexpected changes, you can consider adding the `locations` field to your test to study what location a turn is reported at.
To study a test without post-processing impacts, you can create a copy of the case on a very large grid (like 2000 meters). In such a grid, `turn collapsing` would be essentially disable.
Sadly, there is no general guideline.
### Use Caution
If in doubt, ask another person. Inspect as much of the data as possible (e.g. print un-collapsed steps, turn angles and so on) and use your best judgement, if the new result seems justified.
+2 -2
View File
@@ -19,7 +19,7 @@ if(CMAKE_SIZEOF_VOID_P EQUAL 8)
set(bitness 64)
message(STATUS "Building on a 64 bit system")
else()
message(STATUS "Building on a 32 bit system")
message(WARNING "Building on a 32 bit system is unsupported")
endif()
if(WIN32 AND MSVC_VERSION LESS 1900)
@@ -33,4 +33,4 @@ find_package(LibOSRM REQUIRED)
target_link_libraries(osrm-example ${LibOSRM_LIBRARIES} ${LibOSRM_DEPENDENT_LIBRARIES})
include_directories(SYSTEM ${LibOSRM_INCLUDE_DIRS})
set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} ${LibOSRM_CXXFLAGS}")
set(CMAKE_CXX_FLAGS ${LibOSRM_CXXFLAGS})
-8
View File
@@ -174,11 +174,3 @@ Feature: Bike - Access tags on ways
| cycleway | | no | | x |
| runway | | | yes | |
| cycleway | | | no | x |
Scenario: Bike - Bridleways when access is explicit
Then routability should be
| highway | horse | foot | bicycle | bothw |
| bridleway | | | yes | x |
| bridleway | | yes | | x |
| bridleway | designated | | | |
| bridleway | | | | |
+2 -2
View File
@@ -8,7 +8,7 @@ Feature: Bike - Surfaces
Then routability should be
| highway | surface | bothw |
| cycleway | | 48 s |
| cycleway | asphalt | 47.9 s|
| cycleway | asphalt | 48 s |
| cycleway | cobblestone:flattened | 72 s |
| cycleway | paving_stones | 72 s |
| cycleway | compacted | 72 s |
@@ -26,7 +26,7 @@ Feature: Bike - Surfaces
Then routability should be
| highway | surface | bothw |
| cycleway | | 48 s |
| path | | 59.9 s|
| path | | 60 s |
| track | | 60 s |
| track | asphalt | 60 s |
| path | asphalt | 60 s |
+2 -45
View File
@@ -30,35 +30,6 @@ Feature: Car - Restricted access
| | | no | yes | x |
| | | yes | no | |
Scenario: Car - Access tag hierarchy and forward/backward
Then routability should be
| access | access:forward | access:backward | motorcar | motorcar:forward | motorcar:backward | forw | backw |
| | | | | | | x | x |
| yes | | | | | | x | x |
| yes | no | | | | | | x |
| yes | yes | | no | | | | |
| yes | yes | | yes | no | | | x |
| yes | | | | | | x | x |
| yes | | no | | | | x | |
| yes | | yes | no | | | | |
| yes | | yes | yes | | no | x | |
| no | | | | | | | |
| no | yes | | | | | x | |
| no | no | | yes | | | x | x |
| no | no | | no | yes | | x | |
| no | | | | | | | |
| no | | yes | | | | | x |
| no | | no | yes | | | x | x |
| no | | no | no | | yes | | x |
| | no | | | no | | | x |
| | | no | | | no | x | |
| | no | | | | no | | |
| | | no | no | | | | |
| | no | | | yes | | x | x |
| | | no | | | yes | x | x |
| | yes | | | no | | | x |
| | | yes | | | no | x | |
Scenario: Car - Access tag hierarchy on nodes
Then routability should be
| node/access | node/vehicle | node/motor_vehicle | node/motorcar | bothw |
@@ -178,7 +149,6 @@ Feature: Car - Restricted access
| runway | | | | yes | |
| primary | | | | no | x |
@hov
Scenario: Car - only designated HOV ways are ignored by default
Then routability should be
| highway | hov | bothw |
@@ -186,7 +156,6 @@ Feature: Car - Restricted access
| primary | yes | x |
| primary | no | x |
@hov
Scenario: Car - a way with all lanes HOV-designated is inaccessible by default (similar to hov=designated)
Then routability should be
| highway | hov:lanes:forward | hov:lanes:backward | hov:lanes | oneway | forw | backw |
@@ -197,8 +166,8 @@ Feature: Car - Restricted access
| primary | designated\|no | designated\|no | | | x | x |
| primary | yes\|no | yes\|no | | | x | x |
| primary | | | | | x | x |
| primary | designated | | | -1 | | x |
| primary | | designated | | -1 | | |
| primary | designated | | | -1 | | |
| primary | | designated | | -1 | | x |
| primary | | | designated | yes | | |
| primary | | | designated | -1 | | |
| primary | | | designated\| | yes | x | |
@@ -220,15 +189,3 @@ Feature: Car - Restricted access
Then routability should be
| highway | toll | bothw |
| primary | yes | |
Scenario: Car - directional access tags
Then routability should be
| highway | access | access:forward | access:backward | forw | backw |
| primary | yes | yes | yes | x | x |
| primary | yes | | no | x | |
| primary | yes | no | | | x |
| primary | yes | no | no | | |
| primary | no | no | no | | |
| primary | no | | yes | | x |
| primary | no | yes | | x | |
| primary | no | yes | yes | x | x |
+2 -13
View File
@@ -90,7 +90,7 @@ OSRM will use 4/5 of the projected free-flow speed.
| primary | | 3 | 60 | | 29 km/h | 32 km/h |
| primary | | | | 60 | 52 km/h | 47 km/h |
| primary | | 3 | | 60 | 32 km/h | 29 km/h |
| primary | 15 | | 60 | | 47 km/h | 11 km/h |
| primary | 15 | | 60 | | 47 km/h | 12 km/h |
| primary | 15 | 3 | 60 | | 29 km/h | 7 km/h |
| primary | 15 | | | 60 | 12 km/h | 47 km/h |
| primary | 15 | 3 | | 60 | 7 km/h | 29 km/h |
@@ -109,7 +109,7 @@ OSRM will use 4/5 of the projected free-flow speed.
| primary | | 1 | 60 | | 29 km/h | 32 km/h |
| primary | | | | 60 | 52 km/h | 47 km/h |
| primary | | 1 | | 60 | 32 km/h | 29 km/h |
| primary | 15 | | 60 | | 47 km/h | 11 km/h |
| primary | 15 | | 60 | | 47 km/h | 12 km/h |
| primary | 15 | 1 | 60 | | 29 km/h | 7 km/h |
| primary | 15 | | | 60 | 12 km/h | 47 km/h |
| primary | 15 | 1 | | 60 | 7 km/h | 29 km/h |
@@ -123,14 +123,3 @@ OSRM will use 4/5 of the projected free-flow speed.
| primary | 30 | 1 | -1 | | 23 km/h |
| primary | 30 | 1 | | 15 km/h | 15 km/h |
| primary | 30 | 2 | | 23 km/h | 23 km/h |
Scenario: Car - Forwward/backward maxspeed on reverse oneways
Then routability should be
| highway | maxspeed | maxspeed:forward | maxspeed:backward | oneway | forw | backw |
| primary | | | | -1 | | 52 km/h |
| primary | 30 | | | -1 | | 23 km/h |
| primary | | 30 | | -1 | | 52 km/h |
| primary | | | 30 | -1 | | 23 km/h |
| primary | 20 | 30 | | -1 | | 16 km/h |
| primary | 20 | | 30 | -1 | | 23 km/h |
+13 -13
View File
@@ -78,24 +78,24 @@ Feature: Car - Street names in instructions
Scenario: Inner city expressway with on road
Given the node map
"""
a b . . . c g
`f .
`
.
.
a b c g
f
d
.
.
.
e
"""
And the ways
| nodes | highway | name | name:pronunciation | oneway |
| abc | primary | road | roooaad | |
| cg | primary | road | roooaad | |
| bfd | trunk_link | sliproad | | yes |
| cde | trunk | trunk | truank | yes |
| nodes | highway | name | name:pronunciation |
| abc | primary | road | roooaad |
| cg | primary | road | roooaad |
| bfd | trunk_link | | |
| cde | trunk | trunk | truank |
And the relations
| type | way:from | way:to | node:via | restriction |
+1 -4
View File
@@ -27,10 +27,7 @@ Feature: Basic Routing
When I route I should get
| waypoints | route | summary |
| a,e | road,,1 st,1 st | road, 1 st |
# The via node `d` belongs to `cd`, `de`, `df`, `dg` and depending on the edge
# summary can be "road;street", "road, 1 st;1 st, street", "road, blvd;blvd, street"
# The test must be fixed by #2287
#| a,d,f | road,,,street,street | road;street |
| a,d,f | road,,,street,street | road;street |
| a,e,f | road,,1 st,1 st,1 st,street,street | road, 1 st;1 st, street |
Scenario: Name Empty
+1 -3
View File
@@ -111,9 +111,7 @@ Feature: Traffic - turn penalties
"""
When I route I should get
| from | to | route | time |
# The target point `d` can be in `ad`, `cd`, `deh` and `dhk`
# The test must be fixed by #2287
#| a | d | ad,ad | 10s +-1 |
| a | d | ad,ad | 10s +-1 |
| a | e | ad,def,def | 10s +-1 |
| b | f | bf,bf | 10s +-1 |
| b | g | bf,fg,fg | 20s +-1 |
-8
View File
@@ -95,11 +95,3 @@ Feature: Foot - Access tags on ways
| footway | | no | | x |
| motorway | | | yes | |
| footway | | | no | x |
Scenario: Foot - Bridleways when access is explicit
Then routability should be
| highway | horse | bicycle | foot | bothw |
| bridleway | | | yes | x |
| bridleway | | yes | | |
| bridleway | designated | | | |
| bridleway | | | | |
+15 -24
View File
@@ -5,17 +5,13 @@ Feature: Turn Lane Guidance
Given the profile "car"
Given a grid size of 3 meters
@sliproads
Scenario: Separate Turn Lanes
Given the node map
"""
e
.
a ... b ..... c . g
` .
`... d
.
a b c g
d
f
"""
@@ -45,10 +41,8 @@ Feature: Turn Lane Guidance
Given the node map
"""
e
a . . b . . . c g
` .
` .
` d
a b c g
d
f
"""
@@ -73,22 +67,21 @@ Feature: Turn Lane Guidance
| a,g | in,straight,straight | depart,new name straight,arrive | ,left:false straight:true right:false, |
| a,f | in,cross,cross | depart,turn right,arrive | ,left:false straight:false right:true, |
@sliproads
Scenario: Separate Turn Lanes Next to other turns
Given the node map
"""
. e
a . . b . . . c g
. ` .
. ` .
. d
. f
.
.
.
.
i . . h . . . j
e
a b c g
d
f
i h j
"""
And the ways
@@ -116,7 +109,6 @@ Feature: Turn Lane Guidance
| a,j | in,turn,other,other | depart,turn right,turn left,arrive | ,,left:true right:false, |
| a,i | in,turn,other,other | depart,turn right,turn right,arrive | ,,left:false right:true, |
@todo @2654 @none
#https://github.com/Project-OSRM/osrm-backend/issues/2645
#http://www.openstreetmap.org/export#map=19/52.56054/13.32152
@@ -239,7 +231,6 @@ Feature: Turn Lane Guidance
| a,j | ghough,market,market | depart,turn left,arrive | ,none:true straight:false straight:false straight:false, |
| a,f | ghough,ghough,ghough | depart,continue slight left,arrive | ,none:true straight:true straight:false straight:false, |
Scenario: Check sliproad handler loop's exit condition, Issue #2896
# http://www.openstreetmap.org/way/198481519
Given the node locations
@@ -1,139 +0,0 @@
@routing @guidance @staggered-intersections
Feature: Staggered Intersections
Background:
Given the profile "bicycle"
Given a grid size of 1 meters
# Note the one meter grid size: staggered intersections make zig-zags of a couple of meters only
Scenario: Staggered Intersection - pushing in the middle
Given the node map
"""
j
a b c
d
e f g
h
i
"""
And the ways
| nodes | highway | name | oneway |
| abc | residential | Oak St | |
| efg | residential | Oak St | |
| ihedcj | residential | Cedar Dr | yes |
When I route I should get
| waypoints | route | turns | modes |
| a,g | Oak St,Cedar Dr,Oak St,Oak St | depart,turn right,turn left,arrive | cycling,pushing bike,cycling,cycling |
| g,a | Oak St,Oak St | depart,arrive | cycling,cycling |
Scenario: Staggered Intersection - pushing at start
Given the node map
"""
j
a b c
d
e f g
h
i
"""
And the ways
| nodes | highway | name | oneway |
| cba | residential | Oak St | yes |
| efg | residential | Oak St | |
| ihedcj | residential | Cedar Dr | |
When I route I should get
| waypoints | route | turns | modes |
| a,g | Oak St,Cedar Dr,Oak St,Oak St | depart,turn right,turn left,arrive | pushing bike,cycling,cycling,cycling |
| g,a | Oak St,Oak St | depart,arrive | cycling,cycling |
Scenario: Staggered Intersection - pushing at end
Given the node map
"""
j
a b c
d
e f g
h
i
"""
And the ways
| nodes | highway | name | oneway |
| abc | residential | Oak St | |
| gfe | residential | Oak St | yes |
| ihedcj | residential | Cedar Dr | |
When I route I should get
| waypoints | route | turns | modes |
| a,g | Oak St,Cedar Dr,Oak St,Oak St | depart,turn right,turn left,arrive | cycling,cycling,pushing bike,pushing bike |
| g,a | Oak St,Oak St | depart,arrive | cycling,cycling |
Scenario: Staggered Intersection - pushing at start and end
Given the node map
"""
j
a b c
d
e f g
h
i
"""
And the ways
| nodes | highway | name | oneway |
| cba | residential | Oak St | yes |
| gfe | residential | Oak St | yes |
| ihedcj | residential | Cedar Dr | |
When I route I should get
| waypoints | route | turns | modes |
| a,g | Oak St,Cedar Dr,Oak St,Oak St | depart,turn right,turn left,arrive | pushing bike,cycling,pushing bike,pushing bike |
| g,a | Oak St,Oak St | depart,arrive | cycling,cycling |
Scenario: Staggered Intersection - pushing at start and end
Given the node map
"""
j
a b c
d
e f g
h
i
"""
And the ways
| nodes | highway | name |
| cba | pedestrian | Oak St |
| gfe | pedestrian | Oak St |
| ihedcj | residential | Cedar Dr |
When I route I should get
| waypoints | route | turns | modes |
| a,g | Oak St,Cedar Dr,Oak St,Oak St | depart,turn right,turn left,arrive | pushing bike,cycling,pushing bike,pushing bike |
| g,a | Oak St,Cedar Dr,Oak St,Oak St | depart,turn right,turn left,arrive | pushing bike,cycling,pushing bike,pushing bike |
Scenario: Staggered Intersection - control, all cycling on staggered intersection
Given the node map
"""
j
a b c
d
e f g
h
i
"""
And the ways
| nodes | highway | name |
| cba | residential | Oak St |
| gfe | residential | Oak St |
| ihedcj | residential | Cedar Dr |
When I route I should get
| waypoints | route | turns | modes |
| a,g | Oak St,Oak St | depart,arrive | cycling,cycling |
| g,a | Oak St,Oak St | depart,arrive | cycling,cycling |
-282
View File
@@ -1,282 +0,0 @@
@routing @guidance
Feature: Rotary
Background:
Given the profile "car"
Given a grid size of 30 meters
Scenario: Enter and Exit
Given the node map
"""
a
b
h g c d
e
f
"""
And the ways
| nodes | junction |
| ab | |
| cd | |
| ef | |
| gh | |
| bgecb | circular |
When I route I should get
| waypoints | route | turns |
| a,d | ab,cd,cd | depart,bgecb-exit-3,arrive |
| a,f | ab,ef,ef | depart,bgecb-exit-2,arrive |
| a,h | ab,gh,gh | depart,bgecb-exit-1,arrive |
| d,f | cd,ef,ef | depart,bgecb-exit-3,arrive |
| d,h | cd,gh,gh | depart,bgecb-exit-2,arrive |
| d,a | cd,ab,ab | depart,bgecb-exit-1,arrive |
| f,h | ef,gh,gh | depart,bgecb-exit-3,arrive |
| f,a | ef,ab,ab | depart,bgecb-exit-2,arrive |
| f,d | ef,cd,cd | depart,bgecb-exit-1,arrive |
| h,a | gh,ab,ab | depart,bgecb-exit-3,arrive |
| h,d | gh,cd,cd | depart,bgecb-exit-2,arrive |
| h,f | gh,ef,ef | depart,bgecb-exit-1,arrive |
Scenario: Only Enter
Given the node map
"""
a
b
d c g h
e
f
"""
And the ways
| nodes | junction |
| ab | |
| cd | |
| ef | |
| gh | |
| bcegb | circular |
When I route I should get
| waypoints | route | turns |
| a,c | ab,bcegb,bcegb | depart,bcegb-exit-undefined,arrive |
| a,e | ab,bcegb,bcegb | depart,bcegb-exit-undefined,arrive |
| a,g | ab,bcegb,bcegb | depart,bcegb-exit-undefined,arrive |
| d,e | cd,bcegb,bcegb | depart,bcegb-exit-undefined,arrive |
| d,g | cd,bcegb,bcegb | depart,bcegb-exit-undefined,arrive |
| d,b | cd,bcegb,bcegb | depart,bcegb-exit-undefined,arrive |
| f,g | ef,bcegb,bcegb | depart,bcegb-exit-undefined,arrive |
| f,b | ef,bcegb,bcegb | depart,bcegb-exit-undefined,arrive |
| f,c | ef,bcegb,bcegb | depart,bcegb-exit-undefined,arrive |
| h,b | gh,bcegb,bcegb | depart,bcegb-exit-undefined,arrive |
| h,c | gh,bcegb,bcegb | depart,bcegb-exit-undefined,arrive |
| h,e | gh,bcegb,bcegb | depart,bcegb-exit-undefined,arrive |
Scenario: Only Exit
Given the node map
"""
a
b
d c g h
e
f
"""
And the ways
| nodes | junction |
| ab | |
| cd | |
| ef | |
| gh | |
| bcegb | circular |
When I route I should get
| waypoints | route | turns |
| b,d | bcegb,cd,cd | depart,bcegb-exit-1,arrive |
| b,f | bcegb,ef,ef | depart,bcegb-exit-2,arrive |
| b,h | bcegb,gh,gh | depart,bcegb-exit-3,arrive |
| c,f | bcegb,ef,ef | depart,bcegb-exit-1,arrive |
| c,h | bcegb,gh,gh | depart,bcegb-exit-2,arrive |
| c,a | bcegb,ab,ab | depart,bcegb-exit-3,arrive |
| e,h | bcegb,gh,gh | depart,bcegb-exit-1,arrive |
| e,a | bcegb,ab,ab | depart,bcegb-exit-2,arrive |
| e,d | bcegb,cd,cd | depart,bcegb-exit-3,arrive |
| g,a | bcegb,ab,ab | depart,bcegb-exit-1,arrive |
| g,d | bcegb,cd,cd | depart,bcegb-exit-2,arrive |
| g,f | bcegb,ef,ef | depart,bcegb-exit-3,arrive |
#phantom node snapping can result in a full round-trip here, therefore we cannot test b->a and the other direct exits
Scenario: Drive Around
Given the node map
"""
a
b
d c g h
e
f
"""
And the ways
| nodes | junction |
| ab | |
| cd | |
| ef | |
| gh | |
| bcegb | circular |
When I route I should get
| waypoints | route | turns |
| b,c | bcegb,bcegb | depart,arrive |
| b,e | bcegb,bcegb | depart,arrive |
| b,g | bcegb,bcegb | depart,arrive |
| c,e | bcegb,bcegb | depart,arrive |
| c,g | bcegb,bcegb | depart,arrive |
| c,b | bcegb,bcegb | depart,arrive |
| e,g | bcegb,bcegb | depart,arrive |
| e,b | bcegb,bcegb | depart,arrive |
| e,c | bcegb,bcegb | depart,arrive |
| g,b | bcegb,bcegb | depart,arrive |
| g,c | bcegb,bcegb | depart,arrive |
| g,e | bcegb,bcegb | depart,arrive |
#needs to be adjusted when name-discovery works for entrys
Scenario: Mixed Entry and Exit
Given the node map
"""
c a
j b f
k e
l h d
g i
"""
And the ways
| nodes | junction | oneway |
| abc | | yes |
| def | | yes |
| ghi | | yes |
| jkl | | yes |
| bkheb | circular | yes |
When I route I should get
| waypoints | route | turns |
| a,c | abc,abc,abc | depart,rotary-exit-1,arrive |
| a,l | abc,jkl,jkl | depart,bkheb-exit-2,arrive |
| a,i | abc,ghi,ghi | depart,bkheb-exit-3,arrive |
| a,f | abc,def,def | depart,bkheb-exit-4,arrive |
| d,f | def,def,def | depart,rotary-exit-1,arrive |
| d,c | def,abc,abc | depart,bkheb-exit-2,arrive |
| d,l | def,jkl,jkl | depart,bkheb-exit-3,arrive |
| d,i | def,ghi,ghi | depart,bkheb-exit-4,arrive |
| g,i | ghi,ghi,ghi | depart,rotary-exit-1,arrive |
| g,f | ghi,def,def | depart,bkheb-exit-2,arrive |
| g,c | ghi,abc,abc | depart,bkheb-exit-3,arrive |
| g,l | ghi,jkl,jkl | depart,bkheb-exit-4,arrive |
| j,l | jkl,jkl,jkl | depart,rotary-exit-1,arrive |
| j,i | jkl,ghi,ghi | depart,bkheb-exit-2,arrive |
| j,f | jkl,def,def | depart,bkheb-exit-3,arrive |
| j,c | jkl,abc,abc | depart,bkheb-exit-4,arrive |
Scenario: Collinear in X,Y
Given the node map
"""
a
b
c d f
e
"""
And the ways
| nodes | junction |
| ab | |
| bcdb | circular |
| ce | |
| df | |
When I route I should get
| waypoints | route | turns |
| a,e | ab,ce,ce | depart,bcdb-exit-1,arrive |
| a,f | ab,df,df | depart,bcdb-exit-2,arrive |
Scenario: Collinear in X,Y
Given the node map
"""
a
d
b c f
e
"""
And the ways
| nodes | junction |
| ad | |
| bcdb | circular |
| be | |
| cf | |
When I route I should get
| waypoints | route | turns |
| a,e | ad,be,be | depart,bcdb-exit-1,arrive |
| a,f | ad,cf,cf | depart,bcdb-exit-2,arrive |
Scenario: Collinear in X,Y
Given the node map
"""
a
c
d b f
e
"""
And the ways
| nodes | junction |
| ac | |
| bcdb | circular |
| de | |
| bf | |
When I route I should get
| waypoints | route | turns |
| a,e | ac,de,de | depart,bcdb-exit-1,arrive |
| a,f | ac,bf,bf | depart,bcdb-exit-2,arrive |
Scenario: Collinear in X,Y
Given the node map
"""
f
d c e
b
a
"""
And the ways
| nodes | junction |
| ab | |
| bcdb | circular |
| ce | |
| df | |
When I route I should get
| waypoints | route | turns |
| a,e | ab,ce,ce | depart,bcdb-exit-1,arrive |
| a,f | ab,df,df | depart,bcdb-exit-2,arrive |
Scenario: Collinear in X,Y
Given the node map
"""
f
d c e
b
a
"""
And the ways
| nodes | junction |
| ab | |
| bcdb | circular |
| ce | |
| df | |
When I route I should get
| waypoints | route | turns |
| a,e | ab,ce,ce | depart,bcdb-exit-1,arrive |
| a,f | ab,df,df | depart,bcdb-exit-2,arrive |
-35
View File
@@ -55,38 +55,3 @@ Feature: Collapse
| waypoints | route | turns |
| a,g | road,road,road | depart,continue uturn,arrive |
| d,c | road,road,road | depart,continue uturn,arrive |
Scenario: Forking before a turn (forky)
Given the node map
"""
g
.
c
a . . b .'
`d.
f e
"""
# note: check clooapse.feature for a similar test case where we do not
# classify the situation as Sliproad and therefore keep the fork inst.
And the ways
| nodes | name | oneway | highway |
| ab | road | yes | primary |
| bd | road | yes | primary |
| bc | road | yes | primary |
| de | road | yes | primary |
| fd | cross | no | secondary |
| dc | cross | no | secondary |
| cg | cross | no | secondary |
And the relations
| type | way:from | way:to | node:via | restriction |
| restriction | bd | dc | d | no_left_turn |
| restriction | bc | dc | c | no_right_turn |
When I route I should get
| waypoints | route | turns |
| a,g | road,cross,cross | depart,turn left,arrive |
| a,e | road,road,road | depart,continue right,arrive |
# We should discuss whether the next item should be collapsed to depart,turn right,arrive.
| a,f | road,road,cross,cross | depart,continue slight right,turn right,arrive |
+41 -62
View File
@@ -338,10 +338,10 @@ Feature: Collapse
Given the node map
"""
a f g
| | . '
b-e '
/ /
/ /
b e
c d
"""
@@ -353,13 +353,13 @@ Feature: Collapse
| ge | primary | second | no |
When I route I should get
| waypoints | route | turns |
| d,c | first,first,first | depart,continue uturn,arrive |
| a,f | first,first,first | depart,continue uturn,arrive |
| a,g | first,second,second | depart,turn left,arrive |
| d,g | first,second,second | depart,turn right,arrive |
| g,f | second,first,first | depart,turn right,arrive |
| g,c | second,first,first | depart,turn left,arrive |
| waypoints | route | turns |
| d,c | first,first,first | depart,continue uturn,arrive |
| a,f | first,first,first | depart,continue uturn,arrive |
| a,g | first,second,second | depart,turn left,arrive |
| d,g | first,second,second | depart,turn right,arrive |
| g,f | second,first,first | depart,turn right,arrive |
| g,c | second,first,first | depart,end of road left,arrive |
Scenario: Do not collapse turning roads
Given the node map
@@ -484,23 +484,6 @@ Feature: Collapse
| waypoints | route | turns |
| a,d | road,road | depart,arrive |
Scenario: No Name During Turns - Ferry
Given the node map
"""
a b
c d
"""
And the ways
| nodes | highway | name | route |
| ab | tertiary | road | |
| bc | tertiary | | ferry |
| cd | tertiary | road | |
When I route I should get
| waypoints | route | turns |
| a,d | road,,road,road | depart,notification right,notification left,arrive |
Scenario: No Name During Turns, Random Oneway
Given the node map
"""
@@ -701,15 +684,12 @@ Feature: Collapse
Given the node map
"""
g
.
c
a . . b .'
` d.
a b
d
f e
"""
# as it is right now we don't classify this as a sliproad,
# check collapse-detail.feature for a similar test case
# which removes the fork here due to it being a Sliproad.
And the ways
| nodes | name | oneway | highway |
@@ -727,10 +707,11 @@ Feature: Collapse
| restriction | bc | dc | c | no_right_turn |
When I route I should get
| waypoints | route | turns |
| a,g | road,cross,cross | depart,fork left,arrive |
| a,e | road,road,road | depart,fork slight right,arrive |
| a,f | road,road,cross,cross | depart,fork slight right,turn right,arrive |
| waypoints | route | turns |
| a,g | road,cross,cross | depart,turn left,arrive |
| a,e | road,road,road | depart,continue slight right,arrive |
# We should discuss whether the next item should be collapsed to depart,turn right,arrive.
| a,f | road,road,cross,cross | depart,continue slight right,turn right,arrive |
Scenario: On-Off on Highway
Given the node map
@@ -757,13 +738,12 @@ Feature: Collapse
Scenario: Don't collapse going straight if actual turn
Given the node map
"""
e
c |
\ d - - - f
\|
c e
d f
b
|
|
a
"""
@@ -774,10 +754,10 @@ Feature: Collapse
| df | right | residential |
When I route I should get
| waypoints | route | turns | locations |
| a,c | main,main | depart,arrive | a,c |
| a,e | main,straight,straight | depart,turn straight,arrive | a,b,e |
| a,f | main,straight,right,right | depart,turn straight,turn right,arrive | a,b,d,f |
| waypoints | route | turns |
| a,c | main,main | depart,arrive |
| a,e | main,straight,straight | depart,turn straight,arrive |
| a,f | main,straight,right,right | depart,turn straight,turn right,arrive |
Scenario: Entering a segregated road
Given the node map
@@ -949,17 +929,16 @@ Feature: Collapse
#http://www.openstreetmap.org/#map=19/52.48778/13.30024
Scenario: Hohenzollerdammbrücke
Given a grid size of 10 meters
Given the node map
"""
q s
p o
.. ..
. . . .
.. . .
. . . .
j - i - - - h - - - g - f
> k < > l <
a - b - - - c - - - d - e
. . . .
. . . .
.. ..
m n
t r
@@ -1016,13 +995,13 @@ Feature: Collapse
| restriction | ph | hi | h | no_right_turn |
When I route I should get
| waypoints | route | turns | locations |
| a,e | hohe,hohe | depart,arrive | a,e |
| a,s | hohe,a100,a100 | depart,on ramp left,arrive | a,b,s |
| a,t | hohe,a100,a100 | depart,on ramp right,arrive | a,b,t |
| a,j | | | |
| f,j | hohe,hohe | depart,arrive | f,j |
| a,t | hohe,a100,a100 | depart,on ramp right,arrive | a,b,t |
| f,e | | | |
| q,j | a100,hohe,hohe | depart,turn right,arrive | q,p,j |
| q,e | a100,hohebruecke,hohe | depart,turn left,arrive | q,p,e |
| waypoints | route | turns |
| a,e | hohe,hohe | depart,arrive |
| a,s | hohe,a100,a100 | depart,on ramp left,arrive |
| a,t | hohe,a100,a100 | depart,on ramp right,arrive |
| a,j | | |
| f,j | hohe,hohe | depart,arrive |
| a,t | hohe,a100,a100 | depart,on ramp right,arrive |
| f,e | | |
| q,j | a100,hohe,hohe | depart,turn right,arrive |
| q,e | a100,a100,hohe | depart,continue left,arrive |
+48 -399
View File
@@ -9,32 +9,32 @@ Feature: Slipways and Dedicated Turn Lanes
Given the node map
"""
e
a b . . c d
`h .
`
1 `
.
a b c d
h
1
f
.
g
"""
And the ways
| nodes | highway | name | oneway |
| abc | trunk | first | |
| cd | trunk | first | |
| bhf | trunk_link | | yes |
| cfg | primary | second | yes |
| ec | primary | second | |
| nodes | highway | name |
| abc | trunk | first |
| cd | trunk | first |
| bhf | trunk_link | |
| cfg | primary | second |
| ec | primary | second |
And the relations
| type | way:from | way:to | node:via | restriction |
| restriction | abc | cfg | c | no_right_turn |
When I route I should get
| waypoints | route | turns |
| a,g | first,second,second | depart,turn right,arrive |
| a,1 | first,, | depart,turn right,arrive |
| waypoints | route | turns |
| a,g | first,second,second | depart,turn right,arrive |
| a,1 | first,, | depart,turn slight right,arrive |
Scenario: Turn Instead of Ramp - Max-Speed
Given the node map
@@ -51,21 +51,21 @@ Feature: Slipways and Dedicated Turn Lanes
"""
And the ways
| nodes | highway | name | maxspeed | oneway |
| abc | trunk | first | 70 | |
| cd | trunk | first | 2 | |
| bhf | trunk_link | | 2 | yes |
| cfg | primary | second | 50 | yes |
| ec | primary | second | 50 | |
| nodes | highway | name | maxspeed |
| abc | trunk | first | 70 |
| cd | trunk | first | 2 |
| bhf | trunk_link | | 2 |
| cfg | primary | second | 50 |
| ec | primary | second | 50 |
And the relations
| type | way:from | way:to | node:via | restriction |
| restriction | abc | cfg | c | no_right_turn |
When I route I should get
| waypoints | route | turns |
| a,g | first,second,second | depart,turn right,arrive |
| a,1 | first,, | depart,turn right,arrive |
| waypoints | route | turns |
| a,g | first,second,second | depart,turn right,arrive |
| a,1 | first,, | depart,turn slight right,arrive |
Scenario: Turn Instead of Ramp
@@ -94,8 +94,8 @@ Feature: Slipways and Dedicated Turn Lanes
| efg | primary | second |
When I route I should get
| waypoints | route | turns |
| a,g | first,,second,second | depart,off ramp right,turn straight,arrive |
| waypoints | route | turns |
| a,g | first,,second,second | depart,off ramp slight right,turn straight,arrive |
Scenario: Turn Instead of Ramp
Given the node map
@@ -119,30 +119,30 @@ Feature: Slipways and Dedicated Turn Lanes
| efg | primary | second |
When I route I should get
| waypoints | route | turns |
| a,g | first,,second,second | depart,off ramp right,turn straight,arrive |
| waypoints | route | turns |
| a,g | first,,second,second | depart,off ramp slight right,turn straight,arrive |
Scenario: Inner city expressway with on road
Given the node map
"""
a b . . . c g
`f .
`
.
.
a b c g
f
d
.
.
.
e
"""
And the ways
| nodes | highway | name | oneway |
| abc | primary | road | |
| cg | primary | road | |
| bfd | trunk_link | | yes |
| cde | trunk | trunk | yes |
| nodes | highway | name |
| abc | primary | road |
| cg | primary | road |
| bfd | trunk_link | |
| cde | trunk | trunk |
And the relations
| type | way:from | way:to | node:via | restriction |
@@ -240,8 +240,8 @@ Feature: Slipways and Dedicated Turn Lanes
| qe | secondary_link | Ettlinger Allee | | yes |
When I route I should get
| waypoints | route | turns | ref |
| a,o | Schwarzwaldstrasse,Ettlinger Allee,Ettlinger Allee | depart,turn right,arrive | L561,L561, |
| waypoints | route | turns | ref |
| a,o | Schwarzwaldstrasse,Ettlinger Allee,Ettlinger Allee | depart,turn right,arrive | L561,L561, |
Scenario: Traffic Lights everywhere
#http://map.project-osrm.org/?z=18&center=48.995336%2C8.383813&loc=48.995467%2C8.384548&loc=48.995115%2C8.382761&hl=en&alt=0
@@ -271,11 +271,11 @@ Feature: Slipways and Dedicated Turn Lanes
| jcghf | primary | Brauerstrasse | yes |
When I route I should get
| waypoints | route | turns |
| a,i | Ebertstrasse,Ebertstrasse | depart,arrive |
| a,l | Ebertstrasse,Ebertstrasse | depart,arrive |
| a,f | Ebertstrasse,Brauerstrasse,Brauerstrasse | depart,turn right,arrive |
| a,1 | Ebertstrasse,, | depart,turn slight right,arrive |
| waypoints | route | turns |
| a,i | Ebertstrasse,Ebertstrasse | depart,arrive |
| a,l | Ebertstrasse,Ebertstrasse | depart,arrive |
| a,f | Ebertstrasse,Brauerstrasse,Brauerstrasse | depart,turn right,arrive |
| a,1 | Ebertstrasse,, | depart,turn right,arrive |
#2839
Scenario: Self-Loop
@@ -431,354 +431,3 @@ Feature: Slipways and Dedicated Turn Lanes
When I route I should get
| waypoints | route | turns |
| a,i | road,road,road | depart,fork slight left,arrive |
# The following tests are current false positives / false negatives #3199
@sliproads
# http://www.openstreetmap.org/#map=19/52.59847/13.14815
Scenario: Sliproad Detection
Given the node map
"""
a . . .
. .
b . . . . . . c . . . d
` . .
e . .
` . .
f . .
` . .
g i
` h .
"""
And the ways
| nodes | highway | name |
| abefgh | residential | Nachtigallensteig |
| bcd | residential | Kiebitzsteig |
| cg | residential | Haenflingsteig |
| hid | residential | Waldkauzsteig |
When I route I should get
| waypoints | route | turns |
| a,d | Nachtigallensteig,Kiebitzsteig,Kiebitzsteig | depart,turn left,arrive |
| a,h | Nachtigallensteig,Nachtigallensteig | depart,arrive |
@sliproads
Scenario: Not a obvious Sliproad
Given the node map
"""
d
.
s . a . . b . . c
` .
` e
.`
. `
f g
"""
And the ways
| nodes | highway | name | oneway |
| sabc | primary | sabc | |
| dbef | primary | dbef | yes |
| aeg | primary | aeg | yes |
When I route I should get
| waypoints | route | turns |
| s,f | sabc,aeg,dbef,dbef | depart,turn right,turn right,arrive |
@sliproads
Scenario: Through Street, not a Sliproad although obvious
Given the node map
"""
d
.
s . a . . b . . c
` .
` e
. `
. `
f g
"""
And the ways
| nodes | highway | name | oneway |
| sabc | primary | sabc | |
| dbef | primary | dbef | yes |
| aeg | primary | aeg | yes |
When I route I should get
| waypoints | route | turns |
| s,f | sabc,aeg,dbef,dbef | depart,turn right,turn right,arrive |
@sliproads
Scenario: Sliproad target turn is restricted
Given the node map
"""
d
.
s . a . . . . b . . c
` .
` .
` .
` .
`.
e
.`
f `
. ` g
"""
And the ways
| nodes | highway | name | oneway |
| sa | primary | sabc | |
| abc | primary | sabc | |
| dbe | primary | dbef | yes |
| ef | primary | dbef | |
| ae | primary | aeg | yes |
| eg | primary | aeg | |
# the reason we have to split ways at e is that otherwise we can't handle restrictions via e
And the relations
| type | way:from | way:to | node:via | restriction |
| restriction | ae | ef | e | no_right_turn |
When I route I should get
| waypoints | route | turns |
| s,f | sabc,dbef,dbef | depart,turn right,arrive |
| s,g | sabc,aeg,aeg | depart,turn right,arrive |
@sliproads
Scenario: Not a Sliproad, road not continuing straight
Given the node map
"""
d
.
s . a . . b . . c
` .
` e . . g
"""
And the ways
| nodes | highway | name | oneway |
| sabc | primary | sabc | |
| dbe | primary | dbe | yes |
| aeg | primary | aeg | yes |
When I route I should get
| waypoints | route | turns |
| s,c | sabc,sabc | depart,arrive |
| s,g | sabc,aeg,aeg | depart,turn right,arrive |
@sliproads
Scenario: Intersection too far away with Traffic Light shortly after initial split
Given the node map
"""
d
.
s . a . . . . . . . . . . . . . t . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . b . . c
` . . . . . . . . . . . .
` . . . . . . . . . . . .
` . . . . . . . . . . . .
` . . . . . . . . . . . .
` . . . . . . . . . . . .
` . . . . . . . . . . . .
` . . .
` e
.
f
.
"""
And the nodes
| node | highway |
| t | traffic_signals |
And the ways
| nodes | highway | name | oneway |
| satbc | primary | sabc | |
| dbef | primary | dbef | yes |
| ae | primary | ae | yes |
When I route I should get
| waypoints | route | turns |
| s,f | sabc,ae,dbef,dbef | depart,turn slight right,turn right,arrive |
@sliproads
Scenario: Traffic Signal on Sliproad
Given the node map
"""
d
.
s . a . . . . . b . . c
` .
` .
` .
t .
` .
e
.
.
f
"""
And the nodes
| node | highway |
| t | traffic_signals |
And the ways
| nodes | highway | name | oneway |
| sabc | primary | sabc | |
| dbe | primary | dbe | yes |
| ef | primary | ef | |
| ate | primary | ate | yes |
When I route I should get
| waypoints | route | turns |
| s,f | sabc,ef,ef | depart,turn right,arrive |
@sliproads
Scenario: Sliproad tagged as link
Given the node map
"""
d
.
s . a . . . . . b . . c
` .
` .
` .
` .
` .
e
.
.
f
"""
And the ways
| nodes | highway | name | oneway |
| sabc | motorway | sabc | |
| dbef | motorway | dbef | yes |
| ae | motorway_link | ae | yes |
When I route I should get
| waypoints | route | turns |
| s,f | sabc,dbef,dbef | depart,turn right,arrive |
@sliproads
Scenario: Sliproad with same-ish names
Given the node map
"""
d
.
s . a . . b . . c
` .
. e
..
.
f
.
t
"""
And the ways
| nodes | highway | name | ref | oneway |
| sabc | primary | main | | |
| dbe | primary | crossing | r0 | yes |
| eft | primary | crossing | r0;r1 | yes |
| af | primary | sliproad | | yes |
When I route I should get
| waypoints | route | turns |
| s,t | main,crossing,crossing | depart,turn right,arrive |
@sliproads
Scenario: Not a Sliproad, name mismatch
Given the node map
"""
d
.
s . a . . b . . c
` .
. e
. .
..
.
f
.
t
"""
And the ways
| nodes | highway | name | oneway |
| sabc | primary | main | |
| dbe | primary | top | yes |
| ef | primary | bottom | yes |
| ft | primary | away | yes |
| af | primary | sliproad | yes |
When I route I should get
| waypoints | route | turns |
| s,t | main,away,away | depart,turn right,arrive |
@sliproads
Scenario: Not a Sliproad, low road priority
Given the node map
"""
d
.
s . a . . b . . c
` .
. e
. .
..
.
f
.
t
"""
And the ways
# maxspeed otherwise service road will never be routed over and we won't see instructions
| nodes | highway | name | maxspeed | oneway |
| sabc | primary | main | 30 km/h | |
| dbe | primary | crossing | 30 km/h | yes |
| eft | primary | crossing | 30 km/h | yes |
| ft | primary | away | 30 km/h | yes |
| af | service | sliproad | 30 km/h | yes |
When I route I should get
| waypoints | route | turns |
| s,t | main,away,away | depart,turn right,arrive |
@sliproads
Scenario: Not a Sliproad, more than three roads at target intersection
Given the node map
"""
d
.
s . a . . b . . c
` .
. e
. .
..
. h
f .
. g
t
"""
And the ways
| nodes | highway | name | oneway |
| sabc | primary | main | |
| dbe | primary | top | yes |
| eft | primary | bottom | yes |
| fh | primary | another | |
| fg | primary | another | |
| af | primary | sliproad | yes |
When I route I should get
| waypoints | route | turns |
| s,g | main,sliproad,another,another | depart,turn right,turn left,arrive |
-119
View File
@@ -1,119 +0,0 @@
@routing @guidance
Feature: Exceptions for routing onto low-priority roads
Background:
Given the profile "car"
Given a grid size of 10 meters
Scenario: Straight onto low-priority: same name
Given the node map
"""
c
a b d
e
"""
And the ways
| nodes | highway | name |
| abd | residential | road |
| eb | service | service |
| bc | service | service |
When I route I should get
| waypoints | route | turns |
| c,e | service,service | depart,arrive |
| e,c | service,service | depart,arrive |
Scenario: Straight onto low-priority: onto and from unnamed
Given the node map
"""
c
a b d
e
"""
And the ways
| nodes | highway | name |
| abd | residential | road |
| eb | service | |
| bc | service | |
When I route I should get
| waypoints | route | turns |
| e,c | , | depart,arrive |
| c,e | , | depart,arrive |
Scenario: Straight onto low-priority: unnamed
Given the node map
"""
c
a b d
e
"""
And the ways
| nodes | highway | name |
| abd | residential | road |
| eb | service | service |
| bc | service | |
When I route I should get
| waypoints | route | turns |
| e,c | service, | depart,arrive |
| c,e | ,service,service | depart,turn straight,arrive |
Scenario: Straight onto low-priority
Given the node map
"""
a b c
"""
And the ways
| nodes | highway | name |
| ab | residential | road |
| bc | service | service |
When I route I should get
| waypoints | route | turns |
| a,c | road,service,service | depart,new name straight,arrive |
Scenario: Straight onto low-priority, with driveway
Given the node map
"""
f
a b c
"""
And the ways
| nodes | highway | name |
| ab | residential | road |
| bc | service | road |
| bf | driveway | |
When I route I should get
| waypoints | route | turns |
| a,c | road,road | depart,arrive |
Scenario: Straight onto low-priority, with driveway
Given the node map
"""
f
a b c
"""
And the ways
| nodes | highway | name |
| ab | residential | road |
| bc | service | |
| bf | driveway | |
When I route I should get
| waypoints | route | turns |
| a,c | road, | depart,arrive |
| c,a | ,road,road | depart,new name straight,arrive |
+12 -12
View File
@@ -10,12 +10,12 @@ Feature: Simple Turns
"""
a
b
^
/ \
c d
|\
| e
|
e
f
"""
@@ -96,16 +96,16 @@ Feature: Simple Turns
Given the node map
"""
a
|
.b.
b
c h
| |
| |
1 2
| |
d g
'e'
|
e
f
"""
@@ -1,59 +0,0 @@
@routing @guidance @left-handed
Feature: Basic Roundabout
Background:
Given a grid size of 10 meters
Given the profile file
"""
require 'car'
properties.left_hand_driving = true
"""
Scenario: Roundabout exit counting for left sided driving
And a grid size of 10 meters
And the node map
"""
a
b
h g c d
e
f
"""
And the ways
| nodes | junction |
| ab | |
| cd | |
| ef | |
| gh | |
| bcegb | roundabout |
When I route I should get
| waypoints | route | turns |
| a,d | ab,cd,cd | depart,roundabout turn left exit-1,arrive |
| a,f | ab,ef,ef | depart,roundabout turn straight exit-2,arrive |
| a,h | ab,gh,gh | depart,roundabout turn right exit-3,arrive |
Scenario: Mixed Entry and Exit
And a grid size of 10 meters
And the node map
"""
c a
j b f
k e
l h d
g i
"""
And the ways
| nodes | junction | oneway |
| cba | | yes |
| fed | | yes |
| ihg | | yes |
| lkj | | yes |
| behkb | roundabout | yes |
When I route I should get
| waypoints | route | turns |
| c,a | cba,cba,cba | depart,roundabout-exit-1,arrive |
| l,a | lkj,cba,cba | depart,roundabout-exit-2,arrive |
| i,a | ihg,cba,cba | depart,roundabout-exit-3,arrive |
-67
View File
@@ -38,30 +38,6 @@ Feature: Basic Roundabout
| h,c | gh,bcegb,bcegb | depart,roundabout-exit-undefined,arrive |
| h,e | gh,bcegb,bcegb | depart,roundabout-exit-undefined,arrive |
Scenario: Roundabout With Service
Given the node map
"""
a h
bg
d c
e
f
"""
And the ways
| nodes | junction | highway |
| ab | | primary |
| cd | | primary |
| ef | | service |
| gh | | primary |
| bcegb | roundabout | primary |
When I route I should get
| waypoints | route | turns |
| a,d | ab,cd,cd | depart,roundabout-exit-1,arrive |
| a,h | ab,gh,gh | depart,roundabout-exit-2,arrive |
| a,f | ab,ef,ef | depart,roundabout-exit-2,arrive |
#2927
Scenario: Only Roundabout
Given the node map
@@ -492,46 +468,3 @@ Feature: Basic Roundabout
When I route I should get
| waypoints | route | turns |
| e,h | left,right,right | depart,roundabout-exit-2,arrive |
@3361
Scenario: Bersarinplatz (Not a Roundabout)
Given the node map
"""
a n
b m
c l
d e j k
f h
g i
"""
And the ways
| nodes | junction | name | ref | highway | oneway |
| ab | | Petersburger Strasse | B 96a | primary | yes |
| bc | circular | Bersarinplatz | B 96a | primary | |
| ce | circular | Bersarinplatz | B 96a | primary | |
| ed | | Weidenweg | | residential | |
| ef | circular | Bersarinplatz | B 96a | primary | |
| fg | | Petersburger Strasse | B 96a | primary | yes |
| fh | circular | Bersarinplatz | | secondary | |
| ih | | Petersburger Strasse | B 96a | primary | yes |
| hj | circular | Bersarinplatz | | secondary | |
| jk | | Rigaer Strasse | | residential | |
| jl | circular | Bersarinplatz | | secondary | |
| lm | circular | Bersarinplatz | | secondary | |
| mb | circular | Bersarinplatz | | secondary | |
| mn | | Petersburger Strasse | B 96a | primary | yes |
When I route I should get
| waypoints | route | turns |
| a,g | Petersburger Strasse,Petersburger Strasse,Petersburger Strasse | depart,Bersarinplatz-exit-2,arrive |
| d,g | Weidenweg,Petersburger Strasse,Petersburger Strasse | depart,Bersarinplatz-exit-1,arrive |
| i,k | Petersburger Strasse,Rigaer Strasse,Rigaer Strasse | depart,Bersarinplatz-exit-1,arrive |
| i,n | Petersburger Strasse,Petersburger Strasse,Petersburger Strasse | depart,Bersarinplatz-exit-2,arrive |
| i,d | Petersburger Strasse,Weidenweg,Weidenweg | depart,Bersarinplatz-exit-3,arrive |
| i,g | Petersburger Strasse,Petersburger Strasse,Petersburger Strasse | depart,Bersarinplatz-exit-4,arrive |
@@ -25,7 +25,7 @@ Feature: Staggered Intersections
| jcdehi | residential | Cedar Dr |
When I route I should get
| waypoints | route | turns |
| waypoints | route | turns |
| a,g | Oak St,Oak St | depart,arrive |
| g,a | Oak St,Oak St | depart,arrive |
@@ -98,48 +98,3 @@ Feature: Staggered Intersections
| waypoints | route | turns |
| a,g | Oak St,Cedar Dr,Elm St,Elm St | depart,turn right,turn left,arrive |
| g,a | Elm St,Cedar Dr,Oak St,Oak St | depart,turn right,turn left,arrive |
Scenario: Staggered Intersection: do not collapse if a mode change is involved
Given the node map
"""
j
a b c
d
e f g
h
"""
And the ways
| nodes | highway | name | route |
| abc | primary | to_sea | |
| ef | | to_sea | ferry |
| fg | primary | road | |
| jcdeh | primary | road | |
When I route I should get
| waypoints | route | turns | modes |
| a,g | to_sea,road,to_sea,road,road | depart,turn right,turn left,notification straight,arrive | driving,driving,ferry,driving,driving |
| g,a | road,to_sea,road,to_sea,to_sea | depart,notification straight,turn right,turn left,arrive | driving,ferry,driving,driving,driving |
Scenario: Staggered Intersection: do not collapse intermediary intersections
Given the node map
"""
j
a b c
e f g
d
k l m
i
"""
And the ways
| nodes | highway | name |
| abc | primary | Oak St |
| efg | residential | Elm St |
| klm | residential | Oak St |
| jcedki | residential | Cedar Dr |
When I route I should get
| waypoints | route | turns |
| a,m | Oak St,Cedar Dr,Oak St,Oak St | depart,turn right,turn left,arrive |
| m,a | Oak St,Cedar Dr,Oak St,Oak St | depart,turn right,turn left,arrive |
+40 -132
View File
@@ -201,14 +201,14 @@ Feature: Simple Turns
| ef | residential | road | 2 | yes |
When I route I should get
| waypoints | route | turns | locations |
| a,c | road,road | depart,arrive | a,c |
| c,a | road,road | depart,arrive | c,a |
| g,a | turn,road,road | depart,turn left,arrive | g,b,a |
| g,c | turn,road,road | depart,turn right,arrive | g,b,c |
| g,f | turn,road,road | depart,turn left,arrive | g,e,f |
| c,f | road,road,road | depart,continue right,arrive | c,b,f |
| a,f | road,road,road | depart,continue uturn,arrive | a,b,f |
| waypoints | route | turns |
| a,c | road,road | depart,arrive |
| c,a | road,road | depart,arrive |
| g,a | turn,road,road | depart,turn left,arrive |
| g,c | turn,road,road | depart,turn right,arrive |
| g,f | turn,road | depart,arrive |
| c,f | road,road,road | depart,continue right,arrive |
| a,f | road,road,road | depart,continue uturn,arrive |
# http://www.openstreetmap.org/#map=19/52.48753/13.52838
Scenario: Traffic Circle
@@ -249,7 +249,7 @@ Feature: Simple Turns
When I route I should get
| waypoints | route | turns | intersections |
| a,p | road,road,road | depart,roundabout turn straight exit-1,arrive | true:90;true:165 false:270 false:345,true:90 false:180 true:345;true:270 |
| a,p | road,road,road | depart,roundabout turn straight exit-1,arrive | true:90;true:135 false:270 false:345,true:90 false:180 true:345;true:270 |
Scenario: Splitting Road with many lanes
Given the node map
@@ -317,30 +317,30 @@ Feature: Simple Turns
Scenario: Curved Turn At Cross
Given the node map
"""
h
|
|
|
|
| . b - - - - - - - - - - - - - - - - - - - - - - - a
| .
| .
| c
|
|
|
d
|
|
|
e |
. |
. |
g - - - - - - - - - - - - - - - - - - f |
|
|
|
i
h
|
|
|
|
| . b - - - - - - - - - - - - - - - - - - a
| .
| .
| c
|
|
|
d
|
|
|
e |
. |
. |
g - - - - - - - - - - - - - f |
|
|
|
i
"""
And the ways
@@ -443,9 +443,9 @@ Feature: Simple Turns
| ef | residential | road | 2 | yes |
When I route I should get
| waypoints | route | turns | locations | # |
| g,f | turn,road | depart,arrive | g,f | #could offer an additional turn at `e` if you don't detect the turn in between as curve |
| c,f | road,road,road | depart,continue right,arrive | c,b,f | |
| waypoints | route | turns |
| g,f | turn,road,road | depart,turn left,arrive |
| c,f | road,road,road | depart,continue right,arrive |
#http://www.openstreetmap.org/search?query=52.479264%2013.295617#map=19/52.47926/13.29562
Scenario: Splitting Roads with curved split
@@ -627,14 +627,12 @@ Feature: Simple Turns
| 1,h | ,allee,allee | depart,turn left,arrive |
| 2,h | ,allee,allee | depart,turn left,arrive |
#http://www.openstreetmap.org/#map=18/52.56251/13.32650
@todo
Scenario: Curved Turn on Separated Directions
Given the node map
"""
e d
f c - - - - - - - - - - - j
f - - - - - - - - - - - - - - - c - - - - - - - - - - - j
| l ' |
| ' |
| ' |
@@ -682,58 +680,6 @@ Feature: Simple Turns
| j,o | Kapweg,Kapweg,Kapweg | depart,continue uturn,arrive |
| a,i | Kurt,Kurt,Kurt | depart,continue uturn,arrive |
#http://www.openstreetmap.org/#map=18/52.56251/13.32650
Scenario: Curved Turn on Separated Directions
Given the node map
"""
e d
f c - - - - - - - - - - - j
| l ' |
| ' |
| ' |
| ' |
| ' |
| n |
| |
| ' |
| |
| ' |
| |
| |
| |
|' |
| |
| |
| |
| |
g |
h - - - - - - - - - - - - - - - b - - - - - - - - - - - o
| |
| |
| |
| |
| |
| |
i a
"""
And the ways
| nodes | name | oneway | lanes | highway |
| jc | Kapweg | yes | 3 | primary |
| clngh | Kapweg | yes | | primary_link |
| hbo | Kapweg | yes | 2 | primary |
| efh | Kurt | yes | 4 | secondary |
| hi | Kurt | yes | 3 | primary |
| ab | Kurt | yes | 4 | primary |
| cd | Kurt | yes | 3 | secondary |
| bc | Kurt | yes | 2 | primary |
When I route I should get
| waypoints | route | turns |
| j,i | Kapweg,Kurt,Kurt | depart,turn left,arrive |
| j,o | Kapweg,Kapweg,Kapweg | depart,continue uturn,arrive |
| a,i | Kurt,Kurt,Kurt | depart,continue uturn,arrive |
#http://www.openstreetmap.org/#map=19/52.53731/13.36033
Scenario: Splitting Road to Left
Given the node map
@@ -829,7 +775,7 @@ Feature: Simple Turns
| waypoints | route | turns |
| a,j | Siemens,Siemens,Siemens | depart,continue slight right,arrive |
| a,g | Siemens,Erna,Erna | depart,new name slight left,arrive |
| g,j | Erna,Siemens,Siemens | depart,turn left,arrive |
| g,j | Erna,Siemens,Siemens | depart,turn sharp left,arrive |
| g,a | Erna,Siemens,Siemens | depart,new name slight right,arrive |
#http://www.openstreetmap.org/#map=19/52.51303/13.32170
@@ -1166,9 +1112,8 @@ Feature: Simple Turns
"""
And the ways
| nodes | name | highway | lanes | oneway |
| abc | circled | residential | 1 | no |
| cdefghijklmnopc | circled | residential | 1 | yes |
| nodes | name | highway | lanes |
| abcdefghijklmnopc | circled | residential | 1 |
When I route I should get
| waypoints | bearings | route | turns |
@@ -1223,40 +1168,3 @@ Feature: Simple Turns
When I route I should get
| waypoints | route |
| a,e | ab,bcde,bcde |
@3401
Scenario: Curve With Duplicated Coordinates
Given the node locations
| node | lat | lon | # |
| a | 0.9999280745650984 | 1.0 | |
| b | 0.9999280745650984 | 1.0000179813587253 | |
| c | 0.9999280745650984 | 1.0000359627174509 | |
| d | 0.9999460559238238 | 1.0000674300952204 | |
| e | 0.9999640372825492 | 1.0000809161142643 | |
| f | 0.9999820186412746 | 1.0000854114539457 | |
| g | 1.0 | 1.0000854114539457 | |
| h | 1.0 | 1.0000854114539457 | #same as g |
| z | 0.9999100932063729 | 1.0000179813587253 | |
# g
# |
# f
# '
# e
# '
# d
# '
#a - b - c
# |
# z
And the ways
| nodes | oneway | lanes | # |
| ab | yes | 1 | |
| zb | yes | 1 | |
| bcdefgh | yes | 1 | #intentional duplication |
# we don't care for turn instructions, this is a coordinate extraction bug check
When I route I should get
| waypoints | route | intersections |
| a,g | ab,bcdefgh,bcdefgh | true:90;true:45 false:180 false:270;true:180 |
+13 -35
View File
@@ -44,27 +44,6 @@ Feature: Turn Lane Guidance
| a,c | in,straight,straight | depart,new name straight,arrive | ,straight:true right:false, |
| a,d | in,right,right | depart,turn right,arrive | ,straight:false right:true, |
# Turn Lane onto a ferry could end up breaking in intersection generation
Scenario: Basic Turn Lane 3-way Turn with designated lane
Given the node map
"""
a - b ~ ~ c - e
| |
d f
"""
And the ways
| nodes | turn:lanes:forward | name | route |
| ab | through\|through\|right | ferry-route | |
| bc | through\|through\|right | ferry-route | ferry |
| ce | | ferry-route | |
| bd | | right | |
| cf | | right | |
When I route I should get
| waypoints | route | turns |
| a,e | ferry-route,ferry-route,ferry-route,ferry-route | depart,notification straight,notification straight,arrive |
@simple
Scenario: Basic Turn Lane 4-Way Turn
Given the node map
@@ -116,25 +95,24 @@ Feature: Turn Lane Guidance
Scenario: Basic Turn Lane 4-Way With U-Turn Lane
Given the node map
"""
e
f a-1-b---c
d
e
a 1 b c
d
"""
And the ways
| nodes | turn:lanes | turn:lanes:forward | name | # |
| ab | | reverse;left\|through;right | in | |
| bc | | | straight | |
| bd | | | right | |
| be | | | left | |
| fa | | | uturn-avoider | #due to https://github.com/Project-OSRM/osrm-backend/issues/3359 |
| nodes | turn:lanes | turn:lanes:forward | name |
| ab | | reverse;left\|through;right | in |
| bc | | | straight |
| bd | | | right |
| be | | | left |
When I route I should get
| from | to | bearings | route | turns | lanes | locations |
| a | c | 180,180 180,180 | in,straight,straight | depart,new name straight,arrive | ,left;uturn:false straight;right:true, | a,b,c |
| a | d | 180,180 180,180 | in,right,right | depart,turn right,arrive | ,left;uturn:false straight;right:true, | a,b,d |
| a | e | 180,180 180,180 | in,left,left | depart,turn left,arrive | ,left;uturn:true straight;right:false, | a,b,e |
| 1 | a | 90,2 270,2 | in,in,in | depart,turn uturn,arrive | ,left;uturn:true straight;right:false, | _,b,a |
| from | to | bearings | route | turns | lanes |
| a | c | 180,180 180,180 | in,straight,straight | depart,new name straight,arrive | ,left;uturn:false straight;right:true, |
| a | d | 180,180 180,180 | in,right,right | depart,turn right,arrive | ,left;uturn:false straight;right:true, |
| a | e | 180,180 180,180 | in,left,left | depart,turn left,arrive | ,left;uturn:true straight;right:false, |
| 1 | a | 90,2 270,2 | in,in,in | depart,turn uturn,arrive | ,left;uturn:true straight;right:false, |
#this next test requires decision on how to announce lanes for going straight if there is no turn
+10 -10
View File
@@ -1179,8 +1179,8 @@ Feature: Simple Turns
Scenario: Obvious Index wigh very narrow turn to the right
Given the node map
"""
a - b -.-.- - - c
' ' 'd
a b c
d
"""
And the ways
@@ -1198,8 +1198,8 @@ Feature: Simple Turns
Scenario: Obvious Index wigh very narrow turn to the right
Given the node map
"""
a - b - . -.- - c
e - -'-'d-f
a b c
e d f
"""
And the ways
@@ -1218,8 +1218,8 @@ Feature: Simple Turns
Scenario: Obvious Index wigh very narrow turn to the left
Given the node map
"""
. . .d
a - b -'-'- - - c
d
a b c
"""
And the ways
@@ -1237,8 +1237,8 @@ Feature: Simple Turns
Scenario: Obvious Index wigh very narrow turn to the left
Given the node map
"""
e - -.- d-f
a - b - ' - - - c
e d f
a b c
"""
And the ways
@@ -1373,5 +1373,5 @@ Feature: Simple Turns
| kchm | Alexanderstr | primary | yes |
When I route I should get
| waypoints | turns | route |
| a,d | depart,arrive | Stralauer Str,Holzmarktstr |
| waypoints | turns | route |
| a,d | depart,new name straight,arrive | Stralauer Str,Holzmarktstr,Holzmarktstr |
-16
View File
@@ -3,14 +3,6 @@ Feature: osrm-contract command line options: invalid options
Background:
Given the profile "testbot"
And the node map
"""
a b
"""
And the ways
| nodes |
| ab |
And the data has been extracted
Scenario: osrm-contract - Non-existing option
When I try to run "osrm-contract --fly-me-to-the-moon"
@@ -18,11 +10,3 @@ Feature: osrm-contract command line options: invalid options
And stderr should contain "option"
And stderr should contain "fly-me-to-the-moon"
And it should exit with an error
# This tests the error messages when you try to use --segment-speed-file,
# but osrm-extract has not been run with --generate-edge-lookup
Scenario: osrm-contract - Someone forgot --generate-edge-lookup on osrm-extract
When I try to run "osrm-contract --segment-speed-file /dev/null {processed_file}"
Then stderr should contain "Error while trying to mmap"
Then stderr should contain ".osrm.edge_penalties"
And it should exit with an error
+18 -1
View File
@@ -37,7 +37,7 @@ module.exports = function () {
outputRow[direction] = result[direction].status ?
result[direction].status.toString() : '';
break;
case /^[\d\.]+ s/.test(want):
case /^\d+ s/.test(want):
// the result here can come back as a non-number value like
// `diff`, but we only want to apply the unit when it comes
// back as a number, for tableDiff's literal comparison
@@ -127,6 +127,23 @@ module.exports = function () {
var parseRes = (key, scb) => {
if (result.forw[key] === result.backw[key]) {
result.bothw[key] = result.forw[key];
// FIXME these time and speed checks are stopgaps for precision errors in how
// OSRM returns inconsistent durations for rev/for requests along the same way
} else if (key === 'time') {
var range = [result.forw[key] - 1, result.forw[key] + 1];
if (result.backw[key] >= range[0] && result.backw[key] <= range[1])
// usually when we see minor differences here there's an integer
// duration value and one that comes back with a .9 or .1 rounding.
// This returns the integer one
result.bothw[key] = parseInt(result.forw[key]) === result.forw[key] ? result.forw[key] : result.backw[key];
else
result.bothw[key] = 'diff';
} else if (key === 'speed') {
if (Math.abs(result.backw.time - result.forw.time) < 0.2) {
result.bothw[key] = parseInt(result.forw[key]) === result.forw[key] ? result.forw[key] : result.backw[key];
} else {
result.bothw[key] = 'diff';
}
} else {
result.bothw[key] = 'diff';
}
+16 -12
View File
@@ -48,7 +48,7 @@ Feature: Bearing parameter
Scenario: Testbot - Initial bearing on split way
Given the node map
"""
g d 2 1 c f
g d 1 c f
h a 0 b e
"""
@@ -64,17 +64,21 @@ Feature: Bearing parameter
| ha | yes |
When I route I should get
| from | to | bearings | route | bearing |
| 0 | b | 10 10 | bc,bc | 0->0,0->0 |
| 0 | b | 90 90 | ab,ab | 0->90,90->0 |
| 0 | b | 170 170 | da,da | 0->0,0->0 |
| 0 | b | 189 189 | da,da | 0->0,0->0 |
| 0 | 1 | 90 270 | ab,bc,cd,cd | 0->90,90->0,0->270,270->0 |
| 1 | 2 | 10 10 | bc,bc | 0->0,0->0 |
| 1 | 2 | 90 90 | ab,bc,cd,da,ab,ab | 0->90,90->0,0->270,270->180,180->90,90->0 |
| 1 | 0 | 189 189 | da,da | 0->180,180->0 |
| 1 | 2 | 270 270 | cd,cd | 0->270,270->0 |
| 1 | 2 | 349 349 | | |
| from | to | bearings | route | bearing |
| 0 | b | 10 10 | bc,bc | 0->0,0->0 |
| 0 | b | 90 90 | ab,ab | 0->90,90->0 |
# The returned bearing is wrong here, it's based on the snapped
# coordinates, not the acutal edge bearing. This should be
# fixed one day, but it's only a problem when we snap two vias
# to the same point - DP
#| 0 | b | 170 170 | da | 180 |
#| 0 | b | 189 189 | da | 180 |
| 0 | 1 | 90 270 | ab,bc,cd,cd | 0->90,90->0,0->270,270->0 |
| 1 | d | 10 10 | bc,bc | 0->0,0->0 |
| 1 | d | 90 90 | ab,bc,cd,da,da | 0->90,90->0,0->270,270->180,180->0 |
| 1 | 0 | 189 189 | da,da | 0->180,180->0 |
| 1 | d | 270 270 | cd,cd | 0->270,270->0 |
| 1 | d | 349 349 | | |
Scenario: Testbot - Initial bearing in all direction
Given the node map
+2 -2
View File
@@ -20,5 +20,5 @@ Feature: Geometry Compression
When I route I should get
| from | to | route | distance | speed |
| b | e | abcdef,abcdef | 588.6m | 36 km/h |
| e | b | abcdef,abcdef | 588.6m | 36 km/h |
| b | e | abcdef,abcdef | 588.8m | 36 km/h |
| e | b | abcdef,abcdef | 588.8m | 36 km/h |
-42
View File
@@ -1,42 +0,0 @@
@routing @testbot @nil
Feature: Testbot - Check assigning nil values
Scenario: Assign nil values to all way strings
Given the profile file "testbot" extended with
"""
function way_function (way, result)
result.name = "name"
result.ref = "ref"
result.destinations = "destinations"
result.pronunciation = "pronunciation"
result.turn_lanes_forward = "turn_lanes_forward"
result.turn_lanes_backward = "turn_lanes_backward"
result.name = nil
result.ref = nil
result.destinations = nil
result.pronunciation = nil
result.turn_lanes_forward = nil
result.turn_lanes_backward = nil
result.forward_speed = 10
result.backward_speed = 10
result.forward_mode = mode.driving
result.backward_mode = mode.driving
end
"""
Given the node map
"""
a b c
d
"""
And the ways
| nodes |
| ab |
| bc |
| bd |
When I route I should get
| from | to | route |
| a | d | ,, |
| d | a | ,, |
+25
View File
@@ -83,3 +83,28 @@ Feature: Testbot - side bias
| a,d | ab,cd,cd | depart,roundabout turn left exit-1,arrive |
| a,f | ab,ef,ef | depart,roundabout turn straight exit-2,arrive |
| a,h | ab,gh,gh | depart,roundabout turn right exit-3,arrive |
Scenario: Mixed Entry and Exit
And a grid size of 10 meters
And the node map
"""
c a
j b f
k e
l h d
g i
"""
And the ways
| nodes | junction | oneway |
| cba | | yes |
| fed | | yes |
| ihg | | yes |
| lkj | | yes |
| behkb | roundabout | yes |
When I route I should get
| waypoints | route | turns |
| c,a | cba,cba,cba | depart,roundabout-exit-1,arrive |
| l,a | lkj,cba,cba | depart,roundabout-exit-2,arrive |
| i,a | ihg,cba,cba | depart,roundabout-exit-3,arrive |
-1
View File
@@ -81,7 +81,6 @@ class Contractor
EdgeID
LoadEdgeExpandedGraph(const std::string &edge_based_graph_path,
util::DeallocatingVector<extractor::EdgeBasedEdge> &edge_based_edge_list,
std::vector<EdgeWeight> &node_weights,
const std::string &edge_segment_lookup_path,
const std::string &edge_penalty_path,
const std::vector<std::string> &segment_speed_path,
+21 -23
View File
@@ -6,8 +6,8 @@
#include "util/deallocating_vector.hpp"
#include "util/dynamic_graph.hpp"
#include "util/integer_range.hpp"
#include "util/log.hpp"
#include "util/percent.hpp"
#include "util/simple_logger.hpp"
#include "util/timing_util.hpp"
#include "util/typedefs.hpp"
#include "util/xor_fast_hash.hpp"
@@ -156,10 +156,11 @@ class GraphContractor
#ifndef NDEBUG
if (static_cast<unsigned int>(std::max(diter->weight, 1)) > 24 * 60 * 60 * 10)
{
util::Log(logWARNING) << "Edge weight large -> "
<< static_cast<unsigned int>(std::max(diter->weight, 1))
<< " : " << static_cast<unsigned int>(diter->source) << " -> "
<< static_cast<unsigned int>(diter->target);
util::SimpleLogger().Write(logWARNING)
<< "Edge weight large -> "
<< static_cast<unsigned int>(std::max(diter->weight, 1)) << " : "
<< static_cast<unsigned int>(diter->source) << " -> "
<< static_cast<unsigned int>(diter->target);
}
#endif
edges.emplace_back(diter->source,
@@ -244,14 +245,15 @@ class GraphContractor
}
}
}
util::Log() << "merged " << edges.size() - edge << " edges out of " << edges.size();
util::SimpleLogger().Write() << "merged " << edges.size() - edge << " edges out of "
<< edges.size();
edges.resize(edge);
contractor_graph = std::make_shared<ContractorGraph>(nodes, edges);
edges.clear();
edges.shrink_to_fit();
BOOST_ASSERT(0 == edges.capacity());
util::Log() << "contractor finished initalization";
util::SimpleLogger().Write() << "contractor finished initalization";
}
void Run(double core_factor = 1.0)
@@ -268,6 +270,7 @@ class GraphContractor
const constexpr size_t DeleteGrainSize = 1;
const NodeID number_of_nodes = contractor_graph->GetNumberOfNodes();
util::Percent p(number_of_nodes);
ThreadDataContainer thread_data_list(number_of_nodes);
@@ -289,10 +292,9 @@ class GraphContractor
bool use_cached_node_priorities = !node_levels.empty();
if (use_cached_node_priorities)
{
util::UnbufferedLog log;
log << "using cached node priorities ...";
std::cout << "using cached node priorities ..." << std::flush;
node_priorities.swap(node_levels);
log << "ok";
std::cout << "ok" << std::endl;
}
else
{
@@ -300,8 +302,7 @@ class GraphContractor
node_priorities.resize(number_of_nodes);
node_levels.resize(number_of_nodes);
util::UnbufferedLog log;
log << "initializing elimination PQ ...";
std::cout << "initializing elimination PQ ..." << std::flush;
tbb::parallel_for(tbb::blocked_range<int>(0, number_of_nodes, PQGrainSize),
[this, &node_priorities, &node_depth, &thread_data_list](
const tbb::blocked_range<int> &range) {
@@ -312,14 +313,11 @@ class GraphContractor
this->EvaluateNodePriority(data, node_depth[x], x);
}
});
log << "ok";
std::cout << "ok" << std::endl;
}
BOOST_ASSERT(node_priorities.size() == number_of_nodes);
util::Log() << "preprocessing " << number_of_nodes << " nodes ...";
util::UnbufferedLog log;
util::Percent p(log, number_of_nodes);
std::cout << "preprocessing " << number_of_nodes << " nodes ..." << std::flush;
unsigned current_level = 0;
bool flushed_contractor = false;
@@ -333,7 +331,7 @@ class GraphContractor
new_edge_set; // this one is not explicitely
// cleared since it goes out of
// scope anywa
log << " [flush " << number_of_contracted_nodes << " nodes] ";
std::cout << " [flush " << number_of_contracted_nodes << " nodes] " << std::flush;
// Delete old heap data to free memory that we need for the coming operations
thread_data_list.data.clear();
@@ -601,8 +599,9 @@ class GraphContractor
is_core_node.clear();
}
util::Log() << "[core] " << remaining_nodes.size() << " nodes "
<< contractor_graph->GetNumberOfEdges() << " edges.";
util::SimpleLogger().Write() << "[core] " << remaining_nodes.size() << " nodes "
<< contractor_graph->GetNumberOfEdges() << " edges."
<< std::endl;
thread_data_list.data.clear();
}
@@ -619,9 +618,8 @@ class GraphContractor
template <class Edge> inline void GetEdges(util::DeallocatingVector<Edge> &edges)
{
util::UnbufferedLog log;
log << "Getting edges of minimized graph ";
util::Percent p(log, contractor_graph->GetNumberOfNodes());
util::Percent p(contractor_graph->GetNumberOfNodes());
util::SimpleLogger().Write() << "Getting edges of minimized graph";
const NodeID number_of_nodes = contractor_graph->GetNumberOfNodes();
if (contractor_graph->GetNumberOfNodes())
{
-3
View File
@@ -26,9 +26,6 @@ struct QueryEdge
forward = other.forward;
backward = other.backward;
}
// this ID is either the middle node of the shortcut, or the ID of the edge based node (node
// based edge) storing the appropriate data. If `shortcut` is set to true, we get the middle
// node. Otherwise we see the edge based node to access node data.
NodeID id : 31;
bool shortcut : 1;
int weight : 30;
+10 -14
View File
@@ -42,8 +42,7 @@ std::string modeToString(const extractor::TravelMode mode);
} // namespace detail
template <unsigned POLYLINE_PRECISION, typename ForwardIter>
util::json::String makePolyline(ForwardIter begin, ForwardIter end)
template <unsigned POLYLINE_PRECISION, typename ForwardIter> util::json::String makePolyline(ForwardIter begin, ForwardIter end)
{
return {encodePolyline<POLYLINE_PRECISION>(begin, end)};
}
@@ -54,25 +53,22 @@ util::json::Object makeGeoJSONGeometry(ForwardIter begin, ForwardIter end)
auto num_coordinates = std::distance(begin, end);
BOOST_ASSERT(num_coordinates != 0);
util::json::Object geojson;
geojson.values["type"] = "LineString";
util::json::Array coordinates;
if (num_coordinates > 1)
{
geojson.values["type"] = "LineString";
util::json::Array coordinates;
coordinates.values.reserve(num_coordinates);
auto into = std::back_inserter(coordinates.values);
std::transform(begin, end, into, &detail::coordinateToLonLat);
std::transform(
begin, end, std::back_inserter(coordinates.values), &detail::coordinateToLonLat);
geojson.values["coordinates"] = std::move(coordinates);
}
else if (num_coordinates > 0)
{
// For a single location we create a [location, location] LineString
// instead of a single Point making the GeoJSON output consistent.
coordinates.values.reserve(2);
auto location = detail::coordinateToLonLat(*begin);
coordinates.values.push_back(location);
coordinates.values.push_back(location);
geojson.values["type"] = "Point";
util::json::Array coordinates;
coordinates.values.push_back(detail::coordinateToLonLat(*begin));
geojson.values["coordinates"] = std::move(coordinates);
}
geojson.values["coordinates"] = std::move(coordinates);
return geojson;
}
+6 -6
View File
@@ -196,16 +196,16 @@ class RouteAPI : public BaseAPI
[this, &leg_geometry](const guidance::RouteStep &step) {
if (parameters.geometries == RouteParameters::GeometriesType::Polyline)
{
return static_cast<util::json::Value>(json::makePolyline<100000>(
leg_geometry.locations.begin() + step.geometry_begin,
leg_geometry.locations.begin() + step.geometry_end));
return static_cast<util::json::Value>(
json::makePolyline<100000>(leg_geometry.locations.begin() + step.geometry_begin,
leg_geometry.locations.begin() + step.geometry_end));
}
if (parameters.geometries == RouteParameters::GeometriesType::Polyline6)
{
return static_cast<util::json::Value>(json::makePolyline<1000000>(
leg_geometry.locations.begin() + step.geometry_begin,
leg_geometry.locations.begin() + step.geometry_end));
return static_cast<util::json::Value>(
json::makePolyline<1000000>(leg_geometry.locations.begin() + step.geometry_begin,
leg_geometry.locations.begin() + step.geometry_end));
}
BOOST_ASSERT(parameters.geometries == RouteParameters::GeometriesType::GeoJSON);
+6 -6
View File
@@ -1,7 +1,7 @@
#ifndef OSRM_ENGINE_DATA_WATCHDOG_HPP
#define OSRM_ENGINE_DATA_WATCHDOG_HPP
#include "engine/datafacade/shared_memory_datafacade.hpp"
#include "engine/datafacade/shared_datafacade.hpp"
#include "storage/shared_barriers.hpp"
#include "storage/shared_datatype.hpp"
@@ -102,10 +102,10 @@ class DataWatchdog
boost::upgrade_to_unique_lock<boost::upgrade_mutex> unique_facade_lock(facade_lock);
current_timestamp = *shared_timestamp;
facade = std::make_shared<datafacade::SharedMemoryDataFacade>(shared_barriers,
current_timestamp.layout,
current_timestamp.data,
current_timestamp.timestamp);
facade = std::make_shared<datafacade::SharedDataFacade>(shared_barriers,
current_timestamp.layout,
current_timestamp.data,
current_timestamp.timestamp);
return get_locked_facade();
}
@@ -119,7 +119,7 @@ class DataWatchdog
std::unique_ptr<storage::SharedMemory> shared_regions;
mutable boost::shared_mutex facade_mutex;
std::shared_ptr<datafacade::SharedMemoryDataFacade> facade;
std::shared_ptr<datafacade::SharedDataFacade> facade;
storage::SharedDataTimestamp current_timestamp;
};
}
@@ -0,0 +1,974 @@
#ifndef INTERNAL_DATAFACADE_HPP
#define INTERNAL_DATAFACADE_HPP
// implements all data storage when shared memory is _NOT_ used
#include "engine/datafacade/datafacade_base.hpp"
#include "extractor/guidance/turn_instruction.hpp"
#include "util/guidance/bearing_class.hpp"
#include "util/guidance/entry_class.hpp"
#include "extractor/compressed_edge_container.hpp"
#include "extractor/original_edge_data.hpp"
#include "extractor/profile_properties.hpp"
#include "extractor/query_node.hpp"
#include "storage/io.hpp"
#include "storage/storage_config.hpp"
#include "engine/geospatial_query.hpp"
#include "util/graph_loader.hpp"
#include "util/guidance/turn_bearing.hpp"
#include "util/guidance/turn_lanes.hpp"
#include "util/io.hpp"
#include "util/packed_vector.hpp"
#include "util/range_table.hpp"
#include "util/rectangle.hpp"
#include "util/shared_memory_vector_wrapper.hpp"
#include "util/simple_logger.hpp"
#include "util/static_graph.hpp"
#include "util/static_rtree.hpp"
#include "util/typedefs.hpp"
#include "osrm/coordinate.hpp"
#include <cstddef>
#include <cstdlib>
#include <algorithm>
#include <fstream>
#include <ios>
#include <limits>
#include <memory>
#include <string>
#include <unordered_map>
#include <utility>
#include <vector>
#include <boost/assert.hpp>
#include <boost/filesystem/fstream.hpp>
#include <boost/filesystem/operations.hpp>
#include <boost/filesystem/path.hpp>
#include <boost/thread/tss.hpp>
namespace osrm
{
namespace engine
{
namespace datafacade
{
class InternalDataFacade final : public BaseDataFacade
{
private:
using super = BaseDataFacade;
using QueryGraph = util::StaticGraph<typename super::EdgeData>;
using InputEdge = QueryGraph::InputEdge;
using RTreeLeaf = super::RTreeLeaf;
using InternalRTree =
util::StaticRTree<RTreeLeaf, util::ShM<util::Coordinate, false>::vector, false>;
using InternalGeospatialQuery = GeospatialQuery<InternalRTree, BaseDataFacade>;
InternalDataFacade() {}
unsigned m_check_sum;
std::unique_ptr<QueryGraph> m_query_graph;
std::string m_timestamp;
util::ShM<util::Coordinate, false>::vector m_coordinate_list;
util::PackedVector<OSMNodeID, false> m_osmnodeid_list;
util::ShM<GeometryID, false>::vector m_via_geometry_list;
util::ShM<unsigned, false>::vector m_name_ID_list;
util::ShM<extractor::guidance::TurnInstruction, false>::vector m_turn_instruction_list;
util::ShM<LaneDataID, false>::vector m_lane_data_id;
util::ShM<util::guidance::LaneTupleIdPair, false>::vector m_lane_tuple_id_pairs;
util::ShM<extractor::TravelMode, false>::vector m_travel_mode_list;
util::ShM<char, false>::vector m_names_char_list;
util::ShM<unsigned, false>::vector m_geometry_indices;
util::ShM<NodeID, false>::vector m_geometry_node_list;
util::ShM<EdgeWeight, false>::vector m_geometry_fwd_weight_list;
util::ShM<EdgeWeight, false>::vector m_geometry_rev_weight_list;
util::ShM<bool, false>::vector m_is_core_node;
util::ShM<uint8_t, false>::vector m_datasource_list;
util::ShM<std::string, false>::vector m_datasource_names;
util::ShM<std::uint32_t, false>::vector m_lane_description_offsets;
util::ShM<extractor::guidance::TurnLaneType::Mask, false>::vector m_lane_description_masks;
extractor::ProfileProperties m_profile_properties;
std::unique_ptr<InternalRTree> m_static_rtree;
std::unique_ptr<InternalGeospatialQuery> m_geospatial_query;
boost::filesystem::path ram_index_path;
boost::filesystem::path file_index_path;
util::RangeTable<16, false> m_name_table;
// bearing classes by node based node
util::ShM<BearingClassID, false>::vector m_bearing_class_id_table;
// entry class IDs by edge based egde
util::ShM<EntryClassID, false>::vector m_entry_class_id_list;
// bearings pre/post turn
util::ShM<util::guidance::TurnBearing, false>::vector m_pre_turn_bearing;
util::ShM<util::guidance::TurnBearing, false>::vector m_post_turn_bearing;
// the look-up table for entry classes. An entry class lists the possibility of entry for all
// available turns. For every turn, there is an associated entry class.
util::ShM<util::guidance::EntryClass, false>::vector m_entry_class_table;
// the look-up table for distinct bearing classes. A bearing class lists the available bearings
// at an intersection
util::RangeTable<16, false> m_bearing_ranges_table;
util::ShM<DiscreteBearing, false>::vector m_bearing_values_table;
void LoadProfileProperties(const boost::filesystem::path &properties_path)
{
boost::filesystem::ifstream in_stream(properties_path);
if (!in_stream)
{
throw util::exception("Could not open " + properties_path.string() + " for reading.");
}
const auto properties_size = storage::io::readPropertiesCount();
storage::io::readProperties(in_stream, &m_profile_properties, properties_size);
}
void LoadLaneTupleIdPairs(const boost::filesystem::path &lane_data_path)
{
boost::filesystem::ifstream in_stream(lane_data_path);
if (!in_stream)
{
throw util::exception("Could not open " + lane_data_path.string() + " for reading.");
}
std::uint64_t size;
in_stream.read(reinterpret_cast<char *>(&size), sizeof(size));
m_lane_tuple_id_pairs.resize(size);
in_stream.read(reinterpret_cast<char *>(&m_lane_tuple_id_pairs[0]),
sizeof(m_lane_tuple_id_pairs) * size);
}
void LoadTimestamp(const boost::filesystem::path &timestamp_path)
{
util::SimpleLogger().Write() << "Loading Timestamp";
boost::filesystem::ifstream timestamp_stream(timestamp_path);
if (!timestamp_stream)
{
throw util::exception("Could not open " + timestamp_path.string() + " for reading.");
}
const auto timestamp_size = storage::io::readNumberOfBytes(timestamp_stream);
m_timestamp.resize(timestamp_size);
storage::io::readTimestamp(timestamp_stream, &m_timestamp.front(), timestamp_size);
}
void LoadGraph(const boost::filesystem::path &hsgr_path)
{
boost::filesystem::ifstream hsgr_input_stream(hsgr_path);
if (!hsgr_input_stream)
{
throw util::exception("Could not open " + hsgr_path.string() + " for reading.");
}
const auto header = storage::io::readHSGRHeader(hsgr_input_stream);
m_check_sum = header.checksum;
util::ShM<QueryGraph::NodeArrayEntry, false>::vector node_list(header.number_of_nodes);
util::ShM<QueryGraph::EdgeArrayEntry, false>::vector edge_list(header.number_of_edges);
storage::io::readHSGR(hsgr_input_stream,
node_list.data(),
header.number_of_nodes,
edge_list.data(),
header.number_of_edges);
m_query_graph = std::unique_ptr<QueryGraph>(new QueryGraph(node_list, edge_list));
util::SimpleLogger().Write() << "Data checksum is " << m_check_sum;
}
void LoadNodeAndEdgeInformation(const boost::filesystem::path &nodes_file_path,
const boost::filesystem::path &edges_file_path)
{
boost::filesystem::ifstream nodes_input_stream(nodes_file_path, std::ios::binary);
if (!nodes_input_stream)
{
throw util::exception("Could not open " + nodes_file_path.string() + " for reading.");
}
const auto number_of_coordinates = storage::io::readElementCount(nodes_input_stream);
m_coordinate_list.resize(number_of_coordinates);
m_osmnodeid_list.reserve(number_of_coordinates);
storage::io::readNodes(
nodes_input_stream, m_coordinate_list.data(), m_osmnodeid_list, number_of_coordinates);
boost::filesystem::ifstream edges_input_stream(edges_file_path, std::ios::binary);
if (!edges_input_stream)
{
throw util::exception("Could not open " + edges_file_path.string() + " for reading.");
}
const auto number_of_edges = storage::io::readElementCount(edges_input_stream);
m_via_geometry_list.resize(number_of_edges);
m_name_ID_list.resize(number_of_edges);
m_turn_instruction_list.resize(number_of_edges);
m_lane_data_id.resize(number_of_edges);
m_travel_mode_list.resize(number_of_edges);
m_entry_class_id_list.resize(number_of_edges);
m_pre_turn_bearing.resize(number_of_edges);
m_post_turn_bearing.resize(number_of_edges);
storage::io::readEdges(edges_input_stream,
m_via_geometry_list.data(),
m_name_ID_list.data(),
m_turn_instruction_list.data(),
m_lane_data_id.data(),
m_travel_mode_list.data(),
m_entry_class_id_list.data(),
m_pre_turn_bearing.data(),
m_post_turn_bearing.data(),
number_of_edges);
}
void LoadCoreInformation(const boost::filesystem::path &core_data_file)
{
std::ifstream core_stream(core_data_file.string().c_str(), std::ios::binary);
unsigned number_of_markers;
core_stream.read((char *)&number_of_markers, sizeof(unsigned));
std::vector<char> unpacked_core_markers(number_of_markers);
core_stream.read((char *)unpacked_core_markers.data(), sizeof(char) * number_of_markers);
// in this case we have nothing to do
if (number_of_markers <= 0)
{
return;
}
m_is_core_node.resize(number_of_markers);
for (auto i = 0u; i < number_of_markers; ++i)
{
BOOST_ASSERT(unpacked_core_markers[i] == 0 || unpacked_core_markers[i] == 1);
m_is_core_node[i] = unpacked_core_markers[i] == 1;
}
}
void LoadGeometries(const boost::filesystem::path &geometry_file)
{
std::ifstream geometry_stream(geometry_file.string().c_str(), std::ios::binary);
unsigned number_of_indices = 0;
unsigned number_of_compressed_geometries = 0;
geometry_stream.read((char *)&number_of_indices, sizeof(unsigned));
m_geometry_indices.resize(number_of_indices);
if (number_of_indices > 0)
{
geometry_stream.read((char *)&(m_geometry_indices[0]),
number_of_indices * sizeof(unsigned));
}
geometry_stream.read((char *)&number_of_compressed_geometries, sizeof(unsigned));
BOOST_ASSERT(m_geometry_indices.back() == number_of_compressed_geometries);
m_geometry_node_list.resize(number_of_compressed_geometries);
m_geometry_fwd_weight_list.resize(number_of_compressed_geometries);
m_geometry_rev_weight_list.resize(number_of_compressed_geometries);
if (number_of_compressed_geometries > 0)
{
geometry_stream.read((char *)&(m_geometry_node_list[0]),
number_of_compressed_geometries * sizeof(NodeID));
geometry_stream.read((char *)&(m_geometry_fwd_weight_list[0]),
number_of_compressed_geometries * sizeof(EdgeWeight));
geometry_stream.read((char *)&(m_geometry_rev_weight_list[0]),
number_of_compressed_geometries * sizeof(EdgeWeight));
}
}
void LoadDatasourceInfo(const boost::filesystem::path &datasource_names_file,
const boost::filesystem::path &datasource_indexes_file)
{
boost::filesystem::ifstream datasources_stream(datasource_indexes_file, std::ios::binary);
if (!datasources_stream)
{
throw util::exception("Could not open " + datasource_indexes_file.string() +
" for reading!");
}
BOOST_ASSERT(datasources_stream);
const auto number_of_datasources = storage::io::readElementCount(datasources_stream);
if (number_of_datasources > 0)
{
m_datasource_list.resize(number_of_datasources);
storage::io::readDatasourceIndexes(
datasources_stream, &m_datasource_list.front(), number_of_datasources);
}
boost::filesystem::ifstream datasourcenames_stream(datasource_names_file, std::ios::binary);
if (!datasourcenames_stream)
{
throw util::exception("Could not open " + datasource_names_file.string() +
" for reading!");
}
BOOST_ASSERT(datasourcenames_stream);
const auto datasource_names_data = storage::io::readDatasourceNames(datasourcenames_stream);
m_datasource_names.resize(datasource_names_data.lengths.size());
for (std::size_t i = 0; i < datasource_names_data.lengths.size(); ++i)
{
auto name_begin =
datasource_names_data.names.begin() + datasource_names_data.offsets[i];
auto name_end = datasource_names_data.names.begin() + datasource_names_data.offsets[i] +
datasource_names_data.lengths[i];
m_datasource_names[i] = std::string(name_begin, name_end);
}
}
void LoadRTree()
{
BOOST_ASSERT_MSG(!m_coordinate_list.empty(), "coordinates must be loaded before r-tree");
m_static_rtree.reset(new InternalRTree(ram_index_path, file_index_path, m_coordinate_list));
m_geospatial_query.reset(
new InternalGeospatialQuery(*m_static_rtree, m_coordinate_list, *this));
}
void LoadLaneDescriptions(const boost::filesystem::path &lane_description_file)
{
if (!util::deserializeAdjacencyArray(lane_description_file.string(),
m_lane_description_offsets,
m_lane_description_masks))
util::SimpleLogger().Write(logWARNING) << "Failed to read turn lane descriptions from "
<< lane_description_file.string();
}
void LoadStreetNames(const boost::filesystem::path &names_file)
{
boost::filesystem::ifstream name_stream(names_file, std::ios::binary);
name_stream >> m_name_table;
unsigned number_of_chars = 0;
name_stream.read((char *)&number_of_chars, sizeof(unsigned));
BOOST_ASSERT_MSG(0 != number_of_chars, "name file broken");
m_names_char_list.resize(number_of_chars + 1); //+1 gives sentinel element
name_stream.read((char *)&m_names_char_list[0], number_of_chars * sizeof(char));
if (0 == m_names_char_list.size())
{
util::SimpleLogger().Write(logWARNING) << "list of street names is empty";
}
}
void LoadIntersectionClasses(const boost::filesystem::path &intersection_class_file)
{
std::ifstream intersection_stream(intersection_class_file.string(), std::ios::binary);
if (!intersection_stream)
throw util::exception("Could not open " + intersection_class_file.string() +
" for reading.");
if (!util::readAndCheckFingerprint(intersection_stream))
throw util::exception("Fingeprint does not match in " +
intersection_class_file.string());
{
util::SimpleLogger().Write(logINFO) << "Loading Bearing Class IDs";
std::vector<BearingClassID> bearing_class_id;
if (!util::deserializeVector(intersection_stream, bearing_class_id))
throw util::exception("Reading from " + intersection_class_file.string() +
" failed.");
m_bearing_class_id_table.resize(bearing_class_id.size());
std::copy(
bearing_class_id.begin(), bearing_class_id.end(), &m_bearing_class_id_table[0]);
}
{
util::SimpleLogger().Write(logINFO) << "Loading Bearing Classes";
// read the range table
intersection_stream >> m_bearing_ranges_table;
std::vector<util::guidance::BearingClass> bearing_classes;
// and the actual bearing values
std::uint64_t num_bearings;
intersection_stream.read(reinterpret_cast<char *>(&num_bearings), sizeof(num_bearings));
m_bearing_values_table.resize(num_bearings);
intersection_stream.read(reinterpret_cast<char *>(&m_bearing_values_table[0]),
sizeof(m_bearing_values_table[0]) * num_bearings);
if (!static_cast<bool>(intersection_stream))
throw util::exception("Reading from " + intersection_class_file.string() +
" failed.");
}
{
util::SimpleLogger().Write(logINFO) << "Loading Entry Classes";
std::vector<util::guidance::EntryClass> entry_classes;
if (!util::deserializeVector(intersection_stream, entry_classes))
throw util::exception("Reading from " + intersection_class_file.string() +
" failed.");
m_entry_class_table.resize(entry_classes.size());
std::copy(entry_classes.begin(), entry_classes.end(), &m_entry_class_table[0]);
}
}
public:
virtual ~InternalDataFacade()
{
m_static_rtree.reset();
m_geospatial_query.reset();
}
explicit InternalDataFacade(const storage::StorageConfig &config)
{
ram_index_path = config.ram_index_path;
file_index_path = config.file_index_path;
util::SimpleLogger().Write() << "loading graph data";
LoadGraph(config.hsgr_data_path);
util::SimpleLogger().Write() << "loading edge information";
LoadNodeAndEdgeInformation(config.nodes_data_path, config.edges_data_path);
util::SimpleLogger().Write() << "loading core information";
LoadCoreInformation(config.core_data_path);
util::SimpleLogger().Write() << "loading geometries";
LoadGeometries(config.geometries_path);
util::SimpleLogger().Write() << "loading datasource info";
LoadDatasourceInfo(config.datasource_names_path, config.datasource_indexes_path);
util::SimpleLogger().Write() << "loading timestamp";
LoadTimestamp(config.timestamp_path);
util::SimpleLogger().Write() << "loading profile properties";
LoadProfileProperties(config.properties_path);
util::SimpleLogger().Write() << "loading street names";
LoadStreetNames(config.names_data_path);
util::SimpleLogger().Write() << "loading lane tags";
LoadLaneDescriptions(config.turn_lane_description_path);
util::SimpleLogger().Write() << "loading rtree";
LoadRTree();
util::SimpleLogger().Write() << "loading intersection class data";
LoadIntersectionClasses(config.intersection_class_path);
util::SimpleLogger().Write() << "Loading Lane Data Pairs";
LoadLaneTupleIdPairs(config.turn_lane_data_path);
}
// search graph access
unsigned GetNumberOfNodes() const override final { return m_query_graph->GetNumberOfNodes(); }
unsigned GetNumberOfEdges() const override final { return m_query_graph->GetNumberOfEdges(); }
unsigned GetOutDegree(const NodeID n) const override final
{
return m_query_graph->GetOutDegree(n);
}
NodeID GetTarget(const EdgeID e) const override final { return m_query_graph->GetTarget(e); }
EdgeData &GetEdgeData(const EdgeID e) const override final
{
return m_query_graph->GetEdgeData(e);
}
EdgeID BeginEdges(const NodeID n) const override final { return m_query_graph->BeginEdges(n); }
EdgeID EndEdges(const NodeID n) const override final { return m_query_graph->EndEdges(n); }
EdgeRange GetAdjacentEdgeRange(const NodeID node) const override final
{
return m_query_graph->GetAdjacentEdgeRange(node);
}
// searches for a specific edge
EdgeID FindEdge(const NodeID from, const NodeID to) const override final
{
return m_query_graph->FindEdge(from, to);
}
EdgeID FindEdgeInEitherDirection(const NodeID from, const NodeID to) const override final
{
return m_query_graph->FindEdgeInEitherDirection(from, to);
}
EdgeID
FindEdgeIndicateIfReverse(const NodeID from, const NodeID to, bool &result) const override final
{
return m_query_graph->FindEdgeIndicateIfReverse(from, to, result);
}
EdgeID FindSmallestEdge(const NodeID from,
const NodeID to,
std::function<bool(EdgeData)> filter) const override final
{
return m_query_graph->FindSmallestEdge(from, to, filter);
}
// node and edge information access
util::Coordinate GetCoordinateOfNode(const unsigned id) const override final
{
return m_coordinate_list[id];
}
OSMNodeID GetOSMNodeIDOfNode(const unsigned id) const override final
{
return m_osmnodeid_list.at(id);
}
extractor::guidance::TurnInstruction
GetTurnInstructionForEdgeID(const unsigned id) const override final
{
return m_turn_instruction_list.at(id);
}
extractor::TravelMode GetTravelModeForEdgeID(const unsigned id) const override final
{
return m_travel_mode_list.at(id);
}
std::vector<RTreeLeaf> GetEdgesInBox(const util::Coordinate south_west,
const util::Coordinate north_east) const override final
{
BOOST_ASSERT(m_geospatial_query.get());
const util::RectangleInt2D bbox{
south_west.lon, north_east.lon, south_west.lat, north_east.lat};
return m_geospatial_query->Search(bbox);
}
std::vector<PhantomNodeWithDistance>
NearestPhantomNodesInRange(const util::Coordinate input_coordinate,
const float max_distance) const override final
{
BOOST_ASSERT(m_geospatial_query.get());
return m_geospatial_query->NearestPhantomNodesInRange(input_coordinate, max_distance);
}
std::vector<PhantomNodeWithDistance>
NearestPhantomNodesInRange(const util::Coordinate input_coordinate,
const float max_distance,
const int bearing,
const int bearing_range) const override final
{
BOOST_ASSERT(m_geospatial_query.get());
return m_geospatial_query->NearestPhantomNodesInRange(
input_coordinate, max_distance, bearing, bearing_range);
}
std::vector<PhantomNodeWithDistance>
NearestPhantomNodes(const util::Coordinate input_coordinate,
const unsigned max_results) const override final
{
BOOST_ASSERT(m_geospatial_query.get());
return m_geospatial_query->NearestPhantomNodes(input_coordinate, max_results);
}
std::vector<PhantomNodeWithDistance>
NearestPhantomNodes(const util::Coordinate input_coordinate,
const unsigned max_results,
const double max_distance) const override final
{
BOOST_ASSERT(m_geospatial_query.get());
return m_geospatial_query->NearestPhantomNodes(input_coordinate, max_results, max_distance);
}
std::vector<PhantomNodeWithDistance>
NearestPhantomNodes(const util::Coordinate input_coordinate,
const unsigned max_results,
const int bearing,
const int bearing_range) const override final
{
BOOST_ASSERT(m_geospatial_query.get());
return m_geospatial_query->NearestPhantomNodes(
input_coordinate, max_results, bearing, bearing_range);
}
std::vector<PhantomNodeWithDistance>
NearestPhantomNodes(const util::Coordinate input_coordinate,
const unsigned max_results,
const double max_distance,
const int bearing,
const int bearing_range) const override final
{
BOOST_ASSERT(m_geospatial_query.get());
return m_geospatial_query->NearestPhantomNodes(
input_coordinate, max_results, max_distance, bearing, bearing_range);
}
std::pair<PhantomNode, PhantomNode> NearestPhantomNodeWithAlternativeFromBigComponent(
const util::Coordinate input_coordinate, const double max_distance) const override final
{
BOOST_ASSERT(m_geospatial_query.get());
return m_geospatial_query->NearestPhantomNodeWithAlternativeFromBigComponent(
input_coordinate, max_distance);
}
std::pair<PhantomNode, PhantomNode> NearestPhantomNodeWithAlternativeFromBigComponent(
const util::Coordinate input_coordinate) const override final
{
BOOST_ASSERT(m_geospatial_query.get());
return m_geospatial_query->NearestPhantomNodeWithAlternativeFromBigComponent(
input_coordinate);
}
std::pair<PhantomNode, PhantomNode>
NearestPhantomNodeWithAlternativeFromBigComponent(const util::Coordinate input_coordinate,
const double max_distance,
const int bearing,
const int bearing_range) const override final
{
BOOST_ASSERT(m_geospatial_query.get());
return m_geospatial_query->NearestPhantomNodeWithAlternativeFromBigComponent(
input_coordinate, max_distance, bearing, bearing_range);
}
std::pair<PhantomNode, PhantomNode>
NearestPhantomNodeWithAlternativeFromBigComponent(const util::Coordinate input_coordinate,
const int bearing,
const int bearing_range) const override final
{
BOOST_ASSERT(m_geospatial_query.get());
return m_geospatial_query->NearestPhantomNodeWithAlternativeFromBigComponent(
input_coordinate, bearing, bearing_range);
}
unsigned GetCheckSum() const override final { return m_check_sum; }
unsigned GetNameIndexFromEdgeID(const unsigned id) const override final
{
return m_name_ID_list.at(id);
}
std::string GetNameForID(const unsigned name_id) const override final
{
if (std::numeric_limits<unsigned>::max() == name_id)
{
return "";
}
auto range = m_name_table.GetRange(name_id);
std::string result;
result.reserve(range.size());
if (range.begin() != range.end())
{
result.resize(range.back() - range.front() + 1);
std::copy(m_names_char_list.begin() + range.front(),
m_names_char_list.begin() + range.back() + 1,
result.begin());
}
return result;
}
std::string GetRefForID(const unsigned name_id) const override final
{
// We store the ref after the name, destination and pronunciation of a street.
// We do this to get around the street length limit of 255 which would hit
// if we concatenate these. Order (see extractor_callbacks):
// name (0), destination (1), pronunciation (2), ref (3)
return GetNameForID(name_id + 3);
}
std::string GetPronunciationForID(const unsigned name_id) const override final
{
// We store the pronunciation after the name and destination of a street.
// We do this to get around the street length limit of 255 which would hit
// if we concatenate these. Order (see extractor_callbacks):
// name (0), destination (1), pronunciation (2)
return GetNameForID(name_id + 2);
}
std::string GetDestinationsForID(const unsigned name_id) const override final
{
// We store the destination after the name of a street.
// We do this to get around the street length limit of 255 which would hit
// if we concatenate these. Order (see extractor_callbacks):
// name (0), destination (1), pronunciation (2)
return GetNameForID(name_id + 1);
}
virtual GeometryID GetGeometryIndexForEdgeID(const unsigned id) const override final
{
return m_via_geometry_list.at(id);
}
virtual std::size_t GetCoreSize() const override final { return m_is_core_node.size(); }
virtual bool IsCoreNode(const NodeID id) const override final
{
if (m_is_core_node.size() > 0)
{
return m_is_core_node[id];
}
else
{
return false;
}
}
virtual std::vector<NodeID> GetUncompressedForwardGeometry(const EdgeID id) const override final
{
/*
* NodeID's for geometries are stored in one place for
* both forward and reverse segments along the same bi-
* directional edge. The m_geometry_indices stores
* refences to where to find the beginning of the bi-
* directional edge in the m_geometry_node_list vector. For
* forward geometries of bi-directional edges, edges 2 to
* n of that edge need to be read.
*/
const unsigned begin = m_geometry_indices.at(id);
const unsigned end = m_geometry_indices.at(id + 1);
std::vector<NodeID> result_nodes;
result_nodes.resize(end - begin);
std::copy(m_geometry_node_list.begin() + begin,
m_geometry_node_list.begin() + end,
result_nodes.begin());
return result_nodes;
}
virtual std::vector<NodeID> GetUncompressedReverseGeometry(const EdgeID id) const override final
{
/*
* NodeID's for geometries are stored in one place for
* both forward and reverse segments along the same bi-
* directional edge. The m_geometry_indices stores
* refences to where to find the beginning of the bi-
* directional edge in the m_geometry_node_list vector.
* */
const unsigned begin = m_geometry_indices.at(id);
const unsigned end = m_geometry_indices.at(id + 1);
std::vector<NodeID> result_nodes;
result_nodes.resize(end - begin);
std::copy(m_geometry_node_list.rbegin() + (m_geometry_node_list.size() - end),
m_geometry_node_list.rbegin() + (m_geometry_node_list.size() - begin),
result_nodes.begin());
return result_nodes;
}
virtual std::vector<EdgeWeight>
GetUncompressedForwardWeights(const EdgeID id) const override final
{
/*
* EdgeWeights's for geometries are stored in one place for
* both forward and reverse segments along the same bi-
* directional edge. The m_geometry_indices stores
* refences to where to find the beginning of the bi-
* directional edge in the m_geometry_fwd_weight_list vector.
* */
const unsigned begin = m_geometry_indices.at(id) + 1;
const unsigned end = m_geometry_indices.at(id + 1);
std::vector<EdgeWeight> result_weights;
result_weights.resize(end - begin);
std::copy(m_geometry_fwd_weight_list.begin() + begin,
m_geometry_fwd_weight_list.begin() + end,
result_weights.begin());
return result_weights;
}
virtual std::vector<EdgeWeight>
GetUncompressedReverseWeights(const EdgeID id) const override final
{
/*
* EdgeWeights for geometries are stored in one place for
* both forward and reverse segments along the same bi-
* directional edge. The m_geometry_indices stores
* refences to where to find the beginning of the bi-
* directional edge in the m_geometry_rev_weight_list vector. For
* reverse weights of bi-directional edges, edges 1 to
* n-1 of that edge need to be read in reverse.
*/
const unsigned begin = m_geometry_indices.at(id);
const unsigned end = m_geometry_indices.at(id + 1) - 1;
std::vector<EdgeWeight> result_weights;
result_weights.resize(end - begin);
std::copy(m_geometry_rev_weight_list.rbegin() + (m_geometry_rev_weight_list.size() - end),
m_geometry_rev_weight_list.rbegin() + (m_geometry_rev_weight_list.size() - begin),
result_weights.begin());
return result_weights;
}
// Returns the data source ids that were used to supply the edge
// weights.
virtual std::vector<uint8_t>
GetUncompressedForwardDatasources(const EdgeID id) const override final
{
/*
* Data sources for geometries are stored in one place for
* both forward and reverse segments along the same bi-
* directional edge. The m_geometry_indices stores
* refences to where to find the beginning of the bi-
* directional edge in the m_geometry_list vector. For
* forward datasources of bi-directional edges, edges 2 to
* n of that edge need to be read.
*/
const unsigned begin = m_geometry_indices.at(id) + 1;
const unsigned end = m_geometry_indices.at(id + 1);
std::vector<uint8_t> result_datasources;
result_datasources.resize(end - begin);
// If there was no datasource info, return an array of 0's.
if (m_datasource_list.empty())
{
for (unsigned i = 0; i < end - begin; ++i)
{
result_datasources.push_back(0);
}
}
else
{
std::copy(m_datasource_list.begin() + begin,
m_datasource_list.begin() + end,
result_datasources.begin());
}
return result_datasources;
}
// Returns the data source ids that were used to supply the edge
// weights.
virtual std::vector<uint8_t>
GetUncompressedReverseDatasources(const EdgeID id) const override final
{
/*
* Datasources for geometries are stored in one place for
* both forward and reverse segments along the same bi-
* directional edge. The m_geometry_indices stores
* refences to where to find the beginning of the bi-
* directional edge in the m_geometry_list vector. For
* reverse datasources of bi-directional edges, edges 1 to
* n-1 of that edge need to be read in reverse.
*/
const unsigned begin = m_geometry_indices.at(id);
const unsigned end = m_geometry_indices.at(id + 1) - 1;
std::vector<uint8_t> result_datasources;
result_datasources.resize(end - begin);
// If there was no datasource info, return an array of 0's.
if (m_datasource_list.empty())
{
for (unsigned i = 0; i < end - begin; ++i)
{
result_datasources.push_back(0);
}
}
else
{
std::copy(m_datasource_list.rbegin() + (m_datasource_list.size() - end),
m_datasource_list.rbegin() + (m_datasource_list.size() - begin),
result_datasources.begin());
}
return result_datasources;
}
virtual std::string GetDatasourceName(const uint8_t datasource_name_id) const override final
{
BOOST_ASSERT(m_datasource_names.size() >= 1);
BOOST_ASSERT(m_datasource_names.size() > datasource_name_id);
return m_datasource_names[datasource_name_id];
}
std::string GetTimestamp() const override final { return m_timestamp; }
bool GetContinueStraightDefault() const override final
{
return m_profile_properties.continue_straight_at_waypoint;
}
double GetMapMatchingMaxSpeed() const override final
{
return m_profile_properties.max_speed_for_map_matching;
}
BearingClassID GetBearingClassID(const NodeID nid) const override final
{
return m_bearing_class_id_table.at(nid);
}
util::guidance::BearingClass
GetBearingClass(const BearingClassID bearing_class_id) const override final
{
BOOST_ASSERT(bearing_class_id != INVALID_BEARING_CLASSID);
auto range = m_bearing_ranges_table.GetRange(bearing_class_id);
util::guidance::BearingClass result;
for (auto itr = m_bearing_values_table.begin() + range.front();
itr != m_bearing_values_table.begin() + range.back() + 1;
++itr)
result.add(*itr);
return result;
}
EntryClassID GetEntryClassID(const EdgeID eid) const override final
{
return m_entry_class_id_list.at(eid);
}
util::guidance::TurnBearing PreTurnBearing(const EdgeID eid) const override final
{
return m_pre_turn_bearing.at(eid);
}
util::guidance::TurnBearing PostTurnBearing(const EdgeID eid) const override final
{
return m_post_turn_bearing.at(eid);
}
util::guidance::EntryClass GetEntryClass(const EntryClassID entry_class_id) const override final
{
return m_entry_class_table.at(entry_class_id);
}
bool hasLaneData(const EdgeID id) const override final
{
return m_lane_data_id[id] != INVALID_LANE_DATAID;
}
util::guidance::LaneTupleIdPair GetLaneData(const EdgeID id) const override final
{
BOOST_ASSERT(hasLaneData(id));
return m_lane_tuple_id_pairs[m_lane_data_id[id]];
}
extractor::guidance::TurnLaneDescription
GetTurnDescription(const LaneDescriptionID lane_description_id) const override final
{
if (lane_description_id == INVALID_LANE_DESCRIPTIONID)
return {};
else
return extractor::guidance::TurnLaneDescription(
m_lane_description_masks.begin() + m_lane_description_offsets[lane_description_id],
m_lane_description_masks.begin() +
m_lane_description_offsets[lane_description_id + 1]);
}
};
}
}
}
#endif // INTERNAL_DATAFACADE_HPP
@@ -1,52 +0,0 @@
#ifndef PROCESS_MEMORY_DATAFACADE_HPP
#define PROCESS_MEMORY_DATAFACADE_HPP
// implements all data storage when shared memory is _NOT_ used
#include "storage/storage.hpp"
#include "engine/datafacade/contiguous_internalmem_datafacade_base.hpp"
namespace osrm
{
namespace engine
{
namespace datafacade
{
/**
* This datafacade uses a process-local memory block to load
* data into. The structure and layout is the same as when using
* shared memory, so this class, and the SharedMemoryDataFacade both
* share a common base.
* This class holds a unique_ptr to the memory block, so it
* is auto-freed upon destruction.
*/
class ProcessMemoryDataFacade final : public ContiguousInternalMemoryDataFacadeBase
{
private:
std::unique_ptr<char[]> internal_memory;
std::unique_ptr<storage::DataLayout> internal_layout;
public:
explicit ProcessMemoryDataFacade(const storage::StorageConfig &config)
{
storage::Storage storage(config);
// Calculate the layout/size of the memory block
internal_layout = std::make_unique<storage::DataLayout>();
storage.PopulateLayout(*internal_layout);
// Allocate the memory block, then load data from files into it
internal_memory = std::make_unique<char[]>(internal_layout->GetSizeOfLayout());
storage.PopulateData(*internal_layout, internal_memory.get());
// Adjust all the private m_* members to point to the right places
InitializeInternalPointers(*internal_layout.get(), internal_memory.get());
}
};
}
}
}
#endif // PROCESS_MEMORY_DATAFACADE_HPP
@@ -1,6 +1,11 @@
#ifndef CONTIGUOUS_INTERNALMEM_DATAFACADE_HPP
#define CONTIGUOUS_INTERNALMEM_DATAFACADE_HPP
#ifndef SHARED_DATAFACADE_HPP
#define SHARED_DATAFACADE_HPP
// implements all data storage when shared memory _IS_ used
#include "storage/shared_barriers.hpp"
#include "storage/shared_datatype.hpp"
#include "storage/shared_memory.hpp"
#include "engine/datafacade/datafacade_base.hpp"
#include "extractor/compressed_edge_container.hpp"
@@ -12,13 +17,11 @@
#include "util/guidance/turn_lanes.hpp"
#include "engine/geospatial_query.hpp"
#include "util/exception.hpp"
#include "util/exception_utils.hpp"
#include "util/guidance/turn_bearing.hpp"
#include "util/log.hpp"
#include "util/packed_vector.hpp"
#include "util/range_table.hpp"
#include "util/rectangle.hpp"
#include "util/simple_logger.hpp"
#include "util/static_graph.hpp"
#include "util/static_rtree.hpp"
#include "util/typedefs.hpp"
@@ -44,15 +47,9 @@ namespace engine
namespace datafacade
{
/**
* This base class implements the Datafacade interface for accessing
* data that's stored in a single large block of memory (RAM).
*
* In this case "internal memory" refers to RAM - as opposed to "external memory",
* which usually refers to disk.
*/
class ContiguousInternalMemoryDataFacadeBase : public BaseDataFacade
class SharedDataFacade final : public BaseDataFacade
{
private:
using super = BaseDataFacade;
using QueryGraph = util::StaticGraph<EdgeData, true>;
@@ -66,8 +63,18 @@ class ContiguousInternalMemoryDataFacadeBase : public BaseDataFacade
using SharedGeospatialQuery = GeospatialQuery<SharedRTree, BaseDataFacade>;
using RTreeNode = SharedRTree::TreeNode;
storage::SharedDataLayout *data_layout;
char *shared_memory;
std::shared_ptr<storage::SharedBarriers> shared_barriers;
storage::SharedDataType layout_region;
storage::SharedDataType data_region;
unsigned shared_timestamp;
unsigned m_check_sum;
std::unique_ptr<QueryGraph> m_query_graph;
std::unique_ptr<storage::SharedMemory> m_layout_memory;
std::unique_ptr<storage::SharedMemory> m_large_memory;
std::string m_timestamp;
extractor::ProfileProperties *m_profile_properties;
@@ -114,303 +121,362 @@ class ContiguousInternalMemoryDataFacadeBase : public BaseDataFacade
std::shared_ptr<util::RangeTable<16, true>> m_bearing_ranges_table;
util::ShM<DiscreteBearing, true>::vector m_bearing_values_table;
void InitializeChecksumPointer(storage::DataLayout &data_layout, char *memory_block)
void LoadChecksum()
{
m_check_sum =
*data_layout.GetBlockPtr<unsigned>(memory_block, storage::DataLayout::HSGR_CHECKSUM);
util::Log() << "set checksum: " << m_check_sum;
m_check_sum = *data_layout->GetBlockPtr<unsigned>(shared_memory,
storage::SharedDataLayout::HSGR_CHECKSUM);
util::SimpleLogger().Write() << "set checksum: " << m_check_sum;
}
void InitializeProfilePropertiesPointer(storage::DataLayout &data_layout, char *memory_block)
void LoadProfileProperties()
{
m_profile_properties = data_layout.GetBlockPtr<extractor::ProfileProperties>(
memory_block, storage::DataLayout::PROPERTIES);
m_profile_properties = data_layout->GetBlockPtr<extractor::ProfileProperties>(
shared_memory, storage::SharedDataLayout::PROPERTIES);
}
void InitializeTimestampPointer(storage::DataLayout &data_layout, char *memory_block)
void LoadTimestamp()
{
auto timestamp_ptr =
data_layout.GetBlockPtr<char>(memory_block, storage::DataLayout::TIMESTAMP);
m_timestamp.resize(data_layout.GetBlockSize(storage::DataLayout::TIMESTAMP));
data_layout->GetBlockPtr<char>(shared_memory, storage::SharedDataLayout::TIMESTAMP);
m_timestamp.resize(data_layout->GetBlockSize(storage::SharedDataLayout::TIMESTAMP));
std::copy(timestamp_ptr,
timestamp_ptr + data_layout.GetBlockSize(storage::DataLayout::TIMESTAMP),
timestamp_ptr + data_layout->GetBlockSize(storage::SharedDataLayout::TIMESTAMP),
m_timestamp.begin());
}
void InitializeRTreePointers(storage::DataLayout &data_layout, char *memory_block)
void LoadRTree()
{
BOOST_ASSERT_MSG(!m_coordinate_list.empty(), "coordinates must be loaded before r-tree");
const auto file_index_ptr =
data_layout.GetBlockPtr<char>(memory_block, storage::DataLayout::FILE_INDEX_PATH);
const auto file_index_ptr = data_layout->GetBlockPtr<char>(
shared_memory, storage::SharedDataLayout::FILE_INDEX_PATH);
file_index_path = boost::filesystem::path(file_index_ptr);
if (!boost::filesystem::exists(file_index_path))
{
util::Log(logDEBUG) << "Leaf file name " << file_index_path.string();
util::SimpleLogger().Write(logDEBUG) << "Leaf file name " << file_index_path.string();
throw util::exception("Could not load " + file_index_path.string() +
"Is any data loaded into shared memory?" + SOURCE_REF);
"Is any data loaded into shared memory?");
}
auto tree_ptr =
data_layout.GetBlockPtr<RTreeNode>(memory_block, storage::DataLayout::R_SEARCH_TREE);
auto tree_ptr = data_layout->GetBlockPtr<RTreeNode>(
shared_memory, storage::SharedDataLayout::R_SEARCH_TREE);
m_static_rtree.reset(
new SharedRTree(tree_ptr,
data_layout.num_entries[storage::DataLayout::R_SEARCH_TREE],
data_layout->num_entries[storage::SharedDataLayout::R_SEARCH_TREE],
file_index_path,
m_coordinate_list));
m_geospatial_query.reset(
new SharedGeospatialQuery(*m_static_rtree, m_coordinate_list, *this));
}
void InitializeGraphPointer(storage::DataLayout &data_layout, char *memory_block)
void LoadGraph()
{
auto graph_nodes_ptr =
data_layout.GetBlockPtr<GraphNode>(memory_block, storage::DataLayout::GRAPH_NODE_LIST);
auto graph_nodes_ptr = data_layout->GetBlockPtr<GraphNode>(
shared_memory, storage::SharedDataLayout::GRAPH_NODE_LIST);
auto graph_edges_ptr =
data_layout.GetBlockPtr<GraphEdge>(memory_block, storage::DataLayout::GRAPH_EDGE_LIST);
auto graph_edges_ptr = data_layout->GetBlockPtr<GraphEdge>(
shared_memory, storage::SharedDataLayout::GRAPH_EDGE_LIST);
util::ShM<GraphNode, true>::vector node_list(
graph_nodes_ptr, data_layout.num_entries[storage::DataLayout::GRAPH_NODE_LIST]);
graph_nodes_ptr, data_layout->num_entries[storage::SharedDataLayout::GRAPH_NODE_LIST]);
util::ShM<GraphEdge, true>::vector edge_list(
graph_edges_ptr, data_layout.num_entries[storage::DataLayout::GRAPH_EDGE_LIST]);
graph_edges_ptr, data_layout->num_entries[storage::SharedDataLayout::GRAPH_EDGE_LIST]);
m_query_graph.reset(new QueryGraph(node_list, edge_list));
}
void InitializeNodeAndEdgeInformationPointers(storage::DataLayout &data_layout,
char *memory_block)
void LoadNodeAndEdgeInformation()
{
const auto coordinate_list_ptr = data_layout.GetBlockPtr<util::Coordinate>(
memory_block, storage::DataLayout::COORDINATE_LIST);
m_coordinate_list.reset(coordinate_list_ptr,
data_layout.num_entries[storage::DataLayout::COORDINATE_LIST]);
const auto coordinate_list_ptr = data_layout->GetBlockPtr<util::Coordinate>(
shared_memory, storage::SharedDataLayout::COORDINATE_LIST);
m_coordinate_list.reset(
coordinate_list_ptr,
data_layout->num_entries[storage::SharedDataLayout::COORDINATE_LIST]);
for (unsigned i = 0; i < m_coordinate_list.size(); ++i)
{
BOOST_ASSERT(GetCoordinateOfNode(i).IsValid());
}
const auto osmnodeid_list_ptr = data_layout.GetBlockPtr<std::uint64_t>(
memory_block, storage::DataLayout::OSM_NODE_ID_LIST);
m_osmnodeid_list.reset(osmnodeid_list_ptr,
data_layout.num_entries[storage::DataLayout::OSM_NODE_ID_LIST]);
const auto osmnodeid_list_ptr = data_layout->GetBlockPtr<std::uint64_t>(
shared_memory, storage::SharedDataLayout::OSM_NODE_ID_LIST);
m_osmnodeid_list.reset(
osmnodeid_list_ptr,
data_layout->num_entries[storage::SharedDataLayout::OSM_NODE_ID_LIST]);
// We (ab)use the number of coordinates here because we know we have the same amount of ids
m_osmnodeid_list.set_number_of_entries(
data_layout.num_entries[storage::DataLayout::COORDINATE_LIST]);
data_layout->num_entries[storage::SharedDataLayout::COORDINATE_LIST]);
const auto travel_mode_list_ptr = data_layout.GetBlockPtr<extractor::TravelMode>(
memory_block, storage::DataLayout::TRAVEL_MODE);
const auto travel_mode_list_ptr = data_layout->GetBlockPtr<extractor::TravelMode>(
shared_memory, storage::SharedDataLayout::TRAVEL_MODE);
util::ShM<extractor::TravelMode, true>::vector travel_mode_list(
travel_mode_list_ptr, data_layout.num_entries[storage::DataLayout::TRAVEL_MODE]);
travel_mode_list_ptr, data_layout->num_entries[storage::SharedDataLayout::TRAVEL_MODE]);
m_travel_mode_list = std::move(travel_mode_list);
const auto lane_data_id_ptr =
data_layout.GetBlockPtr<LaneDataID>(memory_block, storage::DataLayout::LANE_DATA_ID);
const auto lane_data_id_ptr = data_layout->GetBlockPtr<LaneDataID>(
shared_memory, storage::SharedDataLayout::LANE_DATA_ID);
util::ShM<LaneDataID, true>::vector lane_data_id(
lane_data_id_ptr, data_layout.num_entries[storage::DataLayout::LANE_DATA_ID]);
lane_data_id_ptr, data_layout->num_entries[storage::SharedDataLayout::LANE_DATA_ID]);
m_lane_data_id = std::move(lane_data_id);
const auto lane_tupel_id_pair_ptr =
data_layout.GetBlockPtr<util::guidance::LaneTupleIdPair>(
memory_block, storage::DataLayout::TURN_LANE_DATA);
data_layout->GetBlockPtr<util::guidance::LaneTupleIdPair>(
shared_memory, storage::SharedDataLayout::TURN_LANE_DATA);
util::ShM<util::guidance::LaneTupleIdPair, true>::vector lane_tupel_id_pair(
lane_tupel_id_pair_ptr, data_layout.num_entries[storage::DataLayout::TURN_LANE_DATA]);
lane_tupel_id_pair_ptr,
data_layout->num_entries[storage::SharedDataLayout::TURN_LANE_DATA]);
m_lane_tupel_id_pairs = std::move(lane_tupel_id_pair);
const auto turn_instruction_list_ptr =
data_layout.GetBlockPtr<extractor::guidance::TurnInstruction>(
memory_block, storage::DataLayout::TURN_INSTRUCTION);
data_layout->GetBlockPtr<extractor::guidance::TurnInstruction>(
shared_memory, storage::SharedDataLayout::TURN_INSTRUCTION);
util::ShM<extractor::guidance::TurnInstruction, true>::vector turn_instruction_list(
turn_instruction_list_ptr,
data_layout.num_entries[storage::DataLayout::TURN_INSTRUCTION]);
data_layout->num_entries[storage::SharedDataLayout::TURN_INSTRUCTION]);
m_turn_instruction_list = std::move(turn_instruction_list);
const auto name_id_list_ptr =
data_layout.GetBlockPtr<unsigned>(memory_block, storage::DataLayout::NAME_ID_LIST);
const auto name_id_list_ptr = data_layout->GetBlockPtr<unsigned>(
shared_memory, storage::SharedDataLayout::NAME_ID_LIST);
util::ShM<unsigned, true>::vector name_id_list(
name_id_list_ptr, data_layout.num_entries[storage::DataLayout::NAME_ID_LIST]);
name_id_list_ptr, data_layout->num_entries[storage::SharedDataLayout::NAME_ID_LIST]);
m_name_ID_list = std::move(name_id_list);
const auto entry_class_id_list_ptr =
data_layout.GetBlockPtr<EntryClassID>(memory_block, storage::DataLayout::ENTRY_CLASSID);
const auto entry_class_id_list_ptr = data_layout->GetBlockPtr<EntryClassID>(
shared_memory, storage::SharedDataLayout::ENTRY_CLASSID);
typename util::ShM<EntryClassID, true>::vector entry_class_id_list(
entry_class_id_list_ptr, data_layout.num_entries[storage::DataLayout::ENTRY_CLASSID]);
entry_class_id_list_ptr,
data_layout->num_entries[storage::SharedDataLayout::ENTRY_CLASSID]);
m_entry_class_id_list = std::move(entry_class_id_list);
const auto pre_turn_bearing_ptr = data_layout.GetBlockPtr<util::guidance::TurnBearing>(
memory_block, storage::DataLayout::PRE_TURN_BEARING);
const auto pre_turn_bearing_ptr = data_layout->GetBlockPtr<util::guidance::TurnBearing>(
shared_memory, storage::SharedDataLayout::PRE_TURN_BEARING);
typename util::ShM<util::guidance::TurnBearing, true>::vector pre_turn_bearing(
pre_turn_bearing_ptr, data_layout.num_entries[storage::DataLayout::PRE_TURN_BEARING]);
pre_turn_bearing_ptr,
data_layout->num_entries[storage::SharedDataLayout::PRE_TURN_BEARING]);
m_pre_turn_bearing = std::move(pre_turn_bearing);
const auto post_turn_bearing_ptr = data_layout.GetBlockPtr<util::guidance::TurnBearing>(
memory_block, storage::DataLayout::POST_TURN_BEARING);
const auto post_turn_bearing_ptr = data_layout->GetBlockPtr<util::guidance::TurnBearing>(
shared_memory, storage::SharedDataLayout::POST_TURN_BEARING);
typename util::ShM<util::guidance::TurnBearing, true>::vector post_turn_bearing(
post_turn_bearing_ptr, data_layout.num_entries[storage::DataLayout::POST_TURN_BEARING]);
post_turn_bearing_ptr,
data_layout->num_entries[storage::SharedDataLayout::POST_TURN_BEARING]);
m_post_turn_bearing = std::move(post_turn_bearing);
}
void InitializeViaNodeListPointer(storage::DataLayout &data_layout, char *memory_block)
void LoadViaNodeList()
{
auto via_geometry_list_ptr =
data_layout.GetBlockPtr<GeometryID>(memory_block, storage::DataLayout::VIA_NODE_LIST);
auto via_geometry_list_ptr = data_layout->GetBlockPtr<GeometryID>(
shared_memory, storage::SharedDataLayout::VIA_NODE_LIST);
util::ShM<GeometryID, true>::vector via_geometry_list(
via_geometry_list_ptr, data_layout.num_entries[storage::DataLayout::VIA_NODE_LIST]);
via_geometry_list_ptr,
data_layout->num_entries[storage::SharedDataLayout::VIA_NODE_LIST]);
m_via_geometry_list = std::move(via_geometry_list);
}
void InitializeNamePointers(storage::DataLayout &data_layout, char *memory_block)
void LoadNames()
{
auto offsets_ptr =
data_layout.GetBlockPtr<unsigned>(memory_block, storage::DataLayout::NAME_OFFSETS);
auto blocks_ptr =
data_layout.GetBlockPtr<IndexBlock>(memory_block, storage::DataLayout::NAME_BLOCKS);
auto offsets_ptr = data_layout->GetBlockPtr<unsigned>(
shared_memory, storage::SharedDataLayout::NAME_OFFSETS);
auto blocks_ptr = data_layout->GetBlockPtr<IndexBlock>(
shared_memory, storage::SharedDataLayout::NAME_BLOCKS);
util::ShM<unsigned, true>::vector name_offsets(
offsets_ptr, data_layout.num_entries[storage::DataLayout::NAME_OFFSETS]);
offsets_ptr, data_layout->num_entries[storage::SharedDataLayout::NAME_OFFSETS]);
util::ShM<IndexBlock, true>::vector name_blocks(
blocks_ptr, data_layout.num_entries[storage::DataLayout::NAME_BLOCKS]);
blocks_ptr, data_layout->num_entries[storage::SharedDataLayout::NAME_BLOCKS]);
auto names_list_ptr =
data_layout.GetBlockPtr<char>(memory_block, storage::DataLayout::NAME_CHAR_LIST);
auto names_list_ptr = data_layout->GetBlockPtr<char>(
shared_memory, storage::SharedDataLayout::NAME_CHAR_LIST);
util::ShM<char, true>::vector names_char_list(
names_list_ptr, data_layout.num_entries[storage::DataLayout::NAME_CHAR_LIST]);
names_list_ptr, data_layout->num_entries[storage::SharedDataLayout::NAME_CHAR_LIST]);
m_name_table = std::make_unique<util::RangeTable<16, true>>(
name_offsets, name_blocks, static_cast<unsigned>(names_char_list.size()));
m_names_char_list = std::move(names_char_list);
}
void InitializeTurnLaneDescriptionsPointers(storage::DataLayout &data_layout,
char *memory_block)
void LoadTurnLaneDescriptions()
{
auto offsets_ptr = data_layout.GetBlockPtr<std::uint32_t>(
memory_block, storage::DataLayout::LANE_DESCRIPTION_OFFSETS);
auto offsets_ptr = data_layout->GetBlockPtr<std::uint32_t>(
shared_memory, storage::SharedDataLayout::LANE_DESCRIPTION_OFFSETS);
util::ShM<std::uint32_t, true>::vector offsets(
offsets_ptr, data_layout.num_entries[storage::DataLayout::LANE_DESCRIPTION_OFFSETS]);
offsets_ptr,
data_layout->num_entries[storage::SharedDataLayout::LANE_DESCRIPTION_OFFSETS]);
m_lane_description_offsets = std::move(offsets);
auto masks_ptr = data_layout.GetBlockPtr<extractor::guidance::TurnLaneType::Mask>(
memory_block, storage::DataLayout::LANE_DESCRIPTION_MASKS);
auto masks_ptr = data_layout->GetBlockPtr<extractor::guidance::TurnLaneType::Mask>(
shared_memory, storage::SharedDataLayout::LANE_DESCRIPTION_MASKS);
util::ShM<extractor::guidance::TurnLaneType::Mask, true>::vector masks(
masks_ptr, data_layout.num_entries[storage::DataLayout::LANE_DESCRIPTION_MASKS]);
masks_ptr, data_layout->num_entries[storage::SharedDataLayout::LANE_DESCRIPTION_MASKS]);
m_lane_description_masks = std::move(masks);
}
void InitializeCoreInformationPointer(storage::DataLayout &data_layout, char *memory_block)
void LoadCoreInformation()
{
auto core_marker_ptr =
data_layout.GetBlockPtr<unsigned>(memory_block, storage::DataLayout::CORE_MARKER);
auto core_marker_ptr = data_layout->GetBlockPtr<unsigned>(
shared_memory, storage::SharedDataLayout::CORE_MARKER);
util::ShM<bool, true>::vector is_core_node(
core_marker_ptr, data_layout.num_entries[storage::DataLayout::CORE_MARKER]);
core_marker_ptr, data_layout->num_entries[storage::SharedDataLayout::CORE_MARKER]);
m_is_core_node = std::move(is_core_node);
}
void InitializeGeometryPointers(storage::DataLayout &data_layout, char *memory_block)
void LoadGeometries()
{
auto geometries_index_ptr =
data_layout.GetBlockPtr<unsigned>(memory_block, storage::DataLayout::GEOMETRIES_INDEX);
auto geometries_index_ptr = data_layout->GetBlockPtr<unsigned>(
shared_memory, storage::SharedDataLayout::GEOMETRIES_INDEX);
util::ShM<unsigned, true>::vector geometry_begin_indices(
geometries_index_ptr, data_layout.num_entries[storage::DataLayout::GEOMETRIES_INDEX]);
geometries_index_ptr,
data_layout->num_entries[storage::SharedDataLayout::GEOMETRIES_INDEX]);
m_geometry_indices = std::move(geometry_begin_indices);
auto geometries_node_list_ptr = data_layout.GetBlockPtr<NodeID>(
memory_block, storage::DataLayout::GEOMETRIES_NODE_LIST);
auto geometries_node_list_ptr = data_layout->GetBlockPtr<NodeID>(
shared_memory, storage::SharedDataLayout::GEOMETRIES_NODE_LIST);
util::ShM<NodeID, true>::vector geometry_node_list(
geometries_node_list_ptr,
data_layout.num_entries[storage::DataLayout::GEOMETRIES_NODE_LIST]);
data_layout->num_entries[storage::SharedDataLayout::GEOMETRIES_NODE_LIST]);
m_geometry_node_list = std::move(geometry_node_list);
auto geometries_fwd_weight_list_ptr = data_layout.GetBlockPtr<EdgeWeight>(
memory_block, storage::DataLayout::GEOMETRIES_FWD_WEIGHT_LIST);
auto geometries_fwd_weight_list_ptr = data_layout->GetBlockPtr<EdgeWeight>(
shared_memory, storage::SharedDataLayout::GEOMETRIES_FWD_WEIGHT_LIST);
util::ShM<EdgeWeight, true>::vector geometry_fwd_weight_list(
geometries_fwd_weight_list_ptr,
data_layout.num_entries[storage::DataLayout::GEOMETRIES_FWD_WEIGHT_LIST]);
data_layout->num_entries[storage::SharedDataLayout::GEOMETRIES_FWD_WEIGHT_LIST]);
m_geometry_fwd_weight_list = std::move(geometry_fwd_weight_list);
auto geometries_rev_weight_list_ptr = data_layout.GetBlockPtr<EdgeWeight>(
memory_block, storage::DataLayout::GEOMETRIES_REV_WEIGHT_LIST);
auto geometries_rev_weight_list_ptr = data_layout->GetBlockPtr<EdgeWeight>(
shared_memory, storage::SharedDataLayout::GEOMETRIES_REV_WEIGHT_LIST);
util::ShM<EdgeWeight, true>::vector geometry_rev_weight_list(
geometries_rev_weight_list_ptr,
data_layout.num_entries[storage::DataLayout::GEOMETRIES_REV_WEIGHT_LIST]);
data_layout->num_entries[storage::SharedDataLayout::GEOMETRIES_REV_WEIGHT_LIST]);
m_geometry_rev_weight_list = std::move(geometry_rev_weight_list);
auto datasources_list_ptr =
data_layout.GetBlockPtr<uint8_t>(memory_block, storage::DataLayout::DATASOURCES_LIST);
auto datasources_list_ptr = data_layout->GetBlockPtr<uint8_t>(
shared_memory, storage::SharedDataLayout::DATASOURCES_LIST);
util::ShM<uint8_t, true>::vector datasources_list(
datasources_list_ptr, data_layout.num_entries[storage::DataLayout::DATASOURCES_LIST]);
datasources_list_ptr,
data_layout->num_entries[storage::SharedDataLayout::DATASOURCES_LIST]);
m_datasource_list = std::move(datasources_list);
auto datasource_name_data_ptr =
data_layout.GetBlockPtr<char>(memory_block, storage::DataLayout::DATASOURCE_NAME_DATA);
auto datasource_name_data_ptr = data_layout->GetBlockPtr<char>(
shared_memory, storage::SharedDataLayout::DATASOURCE_NAME_DATA);
util::ShM<char, true>::vector datasource_name_data(
datasource_name_data_ptr,
data_layout.num_entries[storage::DataLayout::DATASOURCE_NAME_DATA]);
data_layout->num_entries[storage::SharedDataLayout::DATASOURCE_NAME_DATA]);
m_datasource_name_data = std::move(datasource_name_data);
auto datasource_name_offsets_ptr = data_layout.GetBlockPtr<std::size_t>(
memory_block, storage::DataLayout::DATASOURCE_NAME_OFFSETS);
auto datasource_name_offsets_ptr = data_layout->GetBlockPtr<std::size_t>(
shared_memory, storage::SharedDataLayout::DATASOURCE_NAME_OFFSETS);
util::ShM<std::size_t, true>::vector datasource_name_offsets(
datasource_name_offsets_ptr,
data_layout.num_entries[storage::DataLayout::DATASOURCE_NAME_OFFSETS]);
data_layout->num_entries[storage::SharedDataLayout::DATASOURCE_NAME_OFFSETS]);
m_datasource_name_offsets = std::move(datasource_name_offsets);
auto datasource_name_lengths_ptr = data_layout.GetBlockPtr<std::size_t>(
memory_block, storage::DataLayout::DATASOURCE_NAME_LENGTHS);
auto datasource_name_lengths_ptr = data_layout->GetBlockPtr<std::size_t>(
shared_memory, storage::SharedDataLayout::DATASOURCE_NAME_LENGTHS);
util::ShM<std::size_t, true>::vector datasource_name_lengths(
datasource_name_lengths_ptr,
data_layout.num_entries[storage::DataLayout::DATASOURCE_NAME_LENGTHS]);
data_layout->num_entries[storage::SharedDataLayout::DATASOURCE_NAME_LENGTHS]);
m_datasource_name_lengths = std::move(datasource_name_lengths);
}
void InitializeIntersectionClassPointers(storage::DataLayout &data_layout, char *memory_block)
void LoadIntersectionClasses()
{
auto bearing_class_id_ptr = data_layout.GetBlockPtr<BearingClassID>(
memory_block, storage::DataLayout::BEARING_CLASSID);
auto bearing_class_id_ptr = data_layout->GetBlockPtr<BearingClassID>(
shared_memory, storage::SharedDataLayout::BEARING_CLASSID);
typename util::ShM<BearingClassID, true>::vector bearing_class_id_table(
bearing_class_id_ptr, data_layout.num_entries[storage::DataLayout::BEARING_CLASSID]);
bearing_class_id_ptr,
data_layout->num_entries[storage::SharedDataLayout::BEARING_CLASSID]);
m_bearing_class_id_table = std::move(bearing_class_id_table);
auto bearing_class_ptr = data_layout.GetBlockPtr<DiscreteBearing>(
memory_block, storage::DataLayout::BEARING_VALUES);
auto bearing_class_ptr = data_layout->GetBlockPtr<DiscreteBearing>(
shared_memory, storage::SharedDataLayout::BEARING_VALUES);
typename util::ShM<DiscreteBearing, true>::vector bearing_class_table(
bearing_class_ptr, data_layout.num_entries[storage::DataLayout::BEARING_VALUES]);
bearing_class_ptr, data_layout->num_entries[storage::SharedDataLayout::BEARING_VALUES]);
m_bearing_values_table = std::move(bearing_class_table);
auto offsets_ptr =
data_layout.GetBlockPtr<unsigned>(memory_block, storage::DataLayout::BEARING_OFFSETS);
auto blocks_ptr =
data_layout.GetBlockPtr<IndexBlock>(memory_block, storage::DataLayout::BEARING_BLOCKS);
auto offsets_ptr = data_layout->GetBlockPtr<unsigned>(
shared_memory, storage::SharedDataLayout::BEARING_OFFSETS);
auto blocks_ptr = data_layout->GetBlockPtr<IndexBlock>(
shared_memory, storage::SharedDataLayout::BEARING_BLOCKS);
util::ShM<unsigned, true>::vector bearing_offsets(
offsets_ptr, data_layout.num_entries[storage::DataLayout::BEARING_OFFSETS]);
offsets_ptr, data_layout->num_entries[storage::SharedDataLayout::BEARING_OFFSETS]);
util::ShM<IndexBlock, true>::vector bearing_blocks(
blocks_ptr, data_layout.num_entries[storage::DataLayout::BEARING_BLOCKS]);
blocks_ptr, data_layout->num_entries[storage::SharedDataLayout::BEARING_BLOCKS]);
m_bearing_ranges_table = std::make_unique<util::RangeTable<16, true>>(
bearing_offsets, bearing_blocks, static_cast<unsigned>(m_bearing_values_table.size()));
auto entry_class_ptr = data_layout.GetBlockPtr<util::guidance::EntryClass>(
memory_block, storage::DataLayout::ENTRY_CLASS);
auto entry_class_ptr = data_layout->GetBlockPtr<util::guidance::EntryClass>(
shared_memory, storage::SharedDataLayout::ENTRY_CLASS);
typename util::ShM<util::guidance::EntryClass, true>::vector entry_class_table(
entry_class_ptr, data_layout.num_entries[storage::DataLayout::ENTRY_CLASS]);
entry_class_ptr, data_layout->num_entries[storage::SharedDataLayout::ENTRY_CLASS]);
m_entry_class_table = std::move(entry_class_table);
}
public:
void InitializeInternalPointers(storage::DataLayout &data_layout, char *memory_block)
// this function handle the deallocation of the shared memory it we can prove it will not be
// used anymore
virtual ~SharedDataFacade()
{
InitializeGraphPointer(data_layout, memory_block);
InitializeChecksumPointer(data_layout, memory_block);
InitializeNodeAndEdgeInformationPointers(data_layout, memory_block);
InitializeGeometryPointers(data_layout, memory_block);
InitializeTimestampPointer(data_layout, memory_block);
InitializeViaNodeListPointer(data_layout, memory_block);
InitializeNamePointers(data_layout, memory_block);
InitializeTurnLaneDescriptionsPointers(data_layout, memory_block);
InitializeCoreInformationPointer(data_layout, memory_block);
InitializeProfilePropertiesPointer(data_layout, memory_block);
InitializeRTreePointers(data_layout, memory_block);
InitializeIntersectionClassPointers(data_layout, memory_block);
boost::interprocess::scoped_lock<boost::interprocess::named_sharable_mutex> exclusive_lock(
data_region == storage::DATA_1 ? shared_barriers->regions_1_mutex
: shared_barriers->regions_2_mutex,
boost::interprocess::defer_lock);
// if this returns false this is still in use
if (exclusive_lock.try_lock())
{
// Now check if this is still the newest dataset
const boost::interprocess::sharable_lock<boost::interprocess::named_upgradable_mutex>
lock(shared_barriers->current_regions_mutex);
auto shared_regions = storage::makeSharedMemory(storage::CURRENT_REGIONS);
const auto current_timestamp =
static_cast<const storage::SharedDataTimestamp *>(shared_regions->Ptr());
if (current_timestamp->timestamp == shared_timestamp)
{
util::SimpleLogger().Write(logDEBUG) << "Retaining data with shared timestamp "
<< shared_timestamp;
}
else
{
storage::SharedMemory::Remove(data_region);
storage::SharedMemory::Remove(layout_region);
}
}
}
SharedDataFacade(const std::shared_ptr<storage::SharedBarriers> &shared_barriers_,
storage::SharedDataType layout_region_,
storage::SharedDataType data_region_,
unsigned shared_timestamp_)
: shared_barriers(shared_barriers_), layout_region(layout_region_),
data_region(data_region_), shared_timestamp(shared_timestamp_)
{
util::SimpleLogger().Write(logDEBUG) << "Loading new data with shared timestamp "
<< shared_timestamp;
BOOST_ASSERT(storage::SharedMemory::RegionExists(layout_region));
m_layout_memory = storage::makeSharedMemory(layout_region);
data_layout = static_cast<storage::SharedDataLayout *>(m_layout_memory->Ptr());
BOOST_ASSERT(storage::SharedMemory::RegionExists(data_region));
m_large_memory = storage::makeSharedMemory(data_region);
shared_memory = (char *)(m_large_memory->Ptr());
LoadGraph();
LoadChecksum();
LoadNodeAndEdgeInformation();
LoadGeometries();
LoadTimestamp();
LoadViaNodeList();
LoadNames();
LoadTurnLaneDescriptions();
LoadCoreInformation();
LoadProfileProperties();
LoadRTree();
LoadIntersectionClasses();
}
// search graph access
@@ -934,4 +1000,4 @@ class ContiguousInternalMemoryDataFacadeBase : public BaseDataFacade
}
}
#endif // CONTIGUOUS_INTERNALMEM_DATAFACADE_HPP
#endif // SHARED_DATAFACADE_HPP
@@ -1,97 +0,0 @@
#ifndef SHARED_MEMORY_DATAFACADE_HPP
#define SHARED_MEMORY_DATAFACADE_HPP
// implements all data storage when shared memory _IS_ used
#include "storage/shared_barriers.hpp"
#include "storage/shared_datatype.hpp"
#include "storage/shared_memory.hpp"
#include "engine/datafacade/contiguous_internalmem_datafacade_base.hpp"
namespace osrm
{
namespace engine
{
namespace datafacade
{
/**
* This datafacade uses an IPC shared memory block as the data location.
* Many SharedMemoryDataFacade objects can be created that point to the same shared
* memory block.
*/
class SharedMemoryDataFacade : public ContiguousInternalMemoryDataFacadeBase
{
protected:
std::unique_ptr<storage::SharedMemory> m_layout_memory;
std::unique_ptr<storage::SharedMemory> m_large_memory;
std::shared_ptr<storage::SharedBarriers> shared_barriers;
storage::SharedDataType layout_region;
storage::SharedDataType data_region;
unsigned shared_timestamp;
SharedMemoryDataFacade() {}
public:
// this function handle the deallocation of the shared memory it we can prove it will not be
// used anymore. We crash hard here if something goes wrong (noexcept).
virtual ~SharedMemoryDataFacade() noexcept
{
boost::interprocess::scoped_lock<boost::interprocess::named_sharable_mutex> exclusive_lock(
data_region == storage::DATA_1 ? shared_barriers->regions_1_mutex
: shared_barriers->regions_2_mutex,
boost::interprocess::defer_lock);
// if this returns false this is still in use
if (exclusive_lock.try_lock())
{
if (storage::SharedMemory::RegionExists(data_region))
{
BOOST_ASSERT(storage::SharedMemory::RegionExists(layout_region));
// Now check if this is still the newest dataset
const boost::interprocess::sharable_lock<boost::interprocess::named_upgradable_mutex>
lock(shared_barriers->current_regions_mutex);
auto shared_regions = storage::makeSharedMemory(storage::CURRENT_REGIONS);
const auto current_timestamp =
static_cast<const storage::SharedDataTimestamp *>(shared_regions->Ptr());
if (current_timestamp->timestamp == shared_timestamp)
{
util::Log(logDEBUG) << "Retaining data with shared timestamp " << shared_timestamp;
}
else
{
storage::SharedMemory::Remove(data_region);
storage::SharedMemory::Remove(layout_region);
}
}
}
}
SharedMemoryDataFacade(const std::shared_ptr<storage::SharedBarriers> &shared_barriers_,
storage::SharedDataType layout_region_,
storage::SharedDataType data_region_,
unsigned shared_timestamp_)
: shared_barriers(shared_barriers_), layout_region(layout_region_),
data_region(data_region_), shared_timestamp(shared_timestamp_)
{
util::Log(logDEBUG) << "Loading new data with shared timestamp " << shared_timestamp;
BOOST_ASSERT(storage::SharedMemory::RegionExists(layout_region));
m_layout_memory = storage::makeSharedMemory(layout_region);
BOOST_ASSERT(storage::SharedMemory::RegionExists(data_region));
m_large_memory = storage::makeSharedMemory(data_region);
InitializeInternalPointers(*reinterpret_cast<storage::DataLayout *>(m_layout_memory->Ptr()),
reinterpret_cast<char *>(m_large_memory->Ptr()));
}
};
}
}
}
#endif // SHARED_MEMORY_DATAFACADE_HPP
-2
View File
@@ -18,8 +18,6 @@
#include "engine/plugins/trip.hpp"
#include "engine/plugins/viaroute.hpp"
#include "engine/status.hpp"
#include "util/exception.hpp"
#include "util/exception_utils.hpp"
#include "util/json_container.hpp"
#include <memory>
+1 -2
View File
@@ -400,8 +400,7 @@ template <typename RTreeT, typename DataFacadeT> class GeospatialQuery
}
if (data.reverse_segment_id.id != SPECIAL_SEGMENTID)
{
const EdgeWeight difference = reverse_weight * ratio;
reverse_weight -= difference;
reverse_weight *= 1.0 - ratio;
}
auto transformed = PhantomNodeWithDistance{PhantomNode{data,
@@ -6,6 +6,7 @@
#include "engine/datafacade/datafacade_base.hpp"
#include "engine/guidance/leg_geometry.hpp"
#include "engine/guidance/route_step.hpp"
#include "engine/guidance/toolkit.hpp"
#include "engine/internal_route_result.hpp"
#include "engine/phantom_node.hpp"
#include "util/coordinate.hpp"
+12 -8
View File
@@ -8,12 +8,14 @@
#include "engine/guidance/leg_geometry.hpp"
#include "engine/guidance/route_step.hpp"
#include "engine/guidance/step_maneuver.hpp"
#include "engine/guidance/toolkit.hpp"
#include "engine/internal_route_result.hpp"
#include "engine/phantom_node.hpp"
#include "util/bearing.hpp"
#include "util/coordinate.hpp"
#include "util/coordinate_calculation.hpp"
#include "util/guidance/entry_class.hpp"
#include "util/guidance/toolkit.hpp"
#include "util/guidance/turn_lanes.hpp"
#include "util/typedefs.hpp"
@@ -154,7 +156,7 @@ inline std::vector<RouteStep> assembleSteps(const datafacade::BaseDataFacade &fa
intersection.entry.push_back(entry_class.allowsEntry(idx));
}
std::int16_t bearing_in_driving_direction =
util::reverseBearing(std::round(bearings.first));
util::bearing::reverseBearing(std::round(bearings.first));
maneuver = {intersection.location,
bearing_in_driving_direction,
bearings.second,
@@ -214,13 +216,14 @@ inline std::vector<RouteStep> assembleSteps(const datafacade::BaseDataFacade &fa
BOOST_ASSERT(segment_index == number_of_segments - 1);
bearings = detail::getArriveBearings(leg_geometry);
intersection = {target_node.location,
std::vector<short>({static_cast<short>(util::reverseBearing(bearings.first))}),
std::vector<bool>({true}),
0,
Intersection::NO_INDEX,
util::guidance::LaneTuple(),
{}};
intersection = {
target_node.location,
std::vector<short>({static_cast<short>(util::bearing::reverseBearing(bearings.first))}),
std::vector<bool>({true}),
0,
Intersection::NO_INDEX,
util::guidance::LaneTuple(),
{}};
// This step has length zero, the only reason we need it is the target location
maneuver = {intersection.location,
@@ -230,6 +233,7 @@ inline std::vector<RouteStep> assembleSteps(const datafacade::BaseDataFacade &fa
WaypointType::Arrive,
0};
BOOST_ASSERT(!leg_geometry.locations.empty());
steps.push_back(RouteStep{target_node.name_id,
facade.GetNameForID(target_node.name_id),
@@ -1,53 +0,0 @@
#ifndef OSRM_ENGINE_GUIDANCE_POSTPROCESSING_TOOLKIT_HPP_
#define OSRM_ENGINE_GUIDANCE_POSTPROCESSING_TOOLKIT_HPP_
#include "extractor/guidance/turn_instruction.hpp"
#include "engine/guidance/route_step.hpp"
#include <iterator>
#include <utility>
namespace osrm
{
namespace engine
{
namespace guidance
{
// Runs fn on RouteStep sub-ranges determined to be roundabouts.
// The function fn is getting called with a roundabout range as in: [enter, .., leave].
//
// The following situations are taken care for (i.e. we discard them):
// - partial roundabout: enter without exit or exit without enter
// - data issues: no roundabout, exit before enter
template <typename Iter, typename Fn> inline Fn forEachRoundabout(Iter first, Iter last, Fn fn)
{
while (first != last)
{
const auto enter = std::find_if(first, last, [](const RouteStep &step) {
return entersRoundabout(step.maneuver.instruction);
});
// enter has to come before leave, otherwise: faulty data / partial roundabout, skip those
const auto leave = std::find_if(enter, last, [](const RouteStep &step) {
return leavesRoundabout(step.maneuver.instruction);
});
// No roundabouts, or partial one (like start / end inside a roundabout)
if (enter == last || leave == last)
break;
(void)fn(std::make_pair(enter, leave));
// Skip to first step after the currently handled enter / leave pair
first = std::next(leave);
}
return fn;
}
} // namespace guidance
} // namespace engine
} // namespace osrm
#endif /* OSRM_ENGINE_GUIDANCE_POSTPROCESSING_TOOLKIT_HPP_ */
+1 -29
View File
@@ -11,11 +11,10 @@
#include "util/guidance/turn_lanes.hpp"
#include <cstddef>
#include <string>
#include <vector>
#include <boost/range/iterator_range.hpp>
namespace osrm
{
namespace engine
@@ -72,33 +71,6 @@ struct RouteStep
std::size_t geometry_begin;
std::size_t geometry_end;
std::vector<Intersection> intersections;
LaneID numLanesToTheRight() const
{
return intersections.front().lanes.first_lane_from_the_right;
}
LaneID numLanesToTheLeft() const
{
LaneID const total = intersections.front().lane_description.size();
return total - (intersections.front().lanes.lanes_in_turn +
intersections.front().lanes.first_lane_from_the_right);
}
auto lanesToTheLeft() const
{
const auto &description = intersections.front().lane_description;
LaneID num_lanes_left = numLanesToTheLeft();
return boost::make_iterator_range(description.begin(),
description.begin() + num_lanes_left);
}
auto lanesToTheRight() const
{
const auto &description = intersections.front().lane_description;
LaneID num_lanes_right = numLanesToTheRight();
return boost::make_iterator_range(description.end() - num_lanes_right, description.end());
}
};
inline RouteStep getInvalidRouteStep()
+108
View File
@@ -0,0 +1,108 @@
#ifndef OSRM_ENGINE_GUIDANCE_TOOLKIT_HPP_
#define OSRM_ENGINE_GUIDANCE_TOOLKIT_HPP_
#include "extractor/guidance/turn_instruction.hpp"
#include "engine/guidance/route_step.hpp"
#include "util/bearing.hpp"
#include "util/guidance/toolkit.hpp"
#include <algorithm>
#include <iterator>
#include <utility>
namespace osrm
{
namespace engine
{
namespace guidance
{
using util::guidance::entersRoundabout;
using util::guidance::leavesRoundabout;
using util::guidance::staysOnRoundabout;
// Silent Turn Instructions are not to be mentioned to the outside world but
inline bool isSilent(const extractor::guidance::TurnInstruction instruction)
{
return instruction.type == extractor::guidance::TurnType::NoTurn ||
instruction.type == extractor::guidance::TurnType::Suppressed ||
instruction.type == extractor::guidance::TurnType::StayOnRoundabout;
}
inline extractor::guidance::DirectionModifier::Enum angleToDirectionModifier(const double bearing)
{
if (bearing < 135)
{
return extractor::guidance::DirectionModifier::Right;
}
if (bearing <= 225)
{
return extractor::guidance::DirectionModifier::Straight;
}
return extractor::guidance::DirectionModifier::Left;
}
// Runs fn on RouteStep sub-ranges determined to be roundabouts.
// The function fn is getting called with a roundabout range as in: [enter, .., leave].
//
// The following situations are taken care for (i.e. we discard them):
// - partial roundabout: enter without exit or exit without enter
// - data issues: no roundabout, exit before enter
template <typename Iter, typename Fn> inline Fn forEachRoundabout(Iter first, Iter last, Fn fn)
{
while (first != last)
{
const auto enter = std::find_if(first, last, [](const RouteStep &step) {
return entersRoundabout(step.maneuver.instruction);
});
// enter has to come before leave, otherwise: faulty data / partial roundabout, skip those
const auto leave = std::find_if(enter, last, [](const RouteStep &step) {
return leavesRoundabout(step.maneuver.instruction);
});
// No roundabouts, or partial one (like start / end inside a roundabout)
if (enter == last || leave == last)
break;
(void)fn(std::make_pair(enter, leave));
// Skip to first step after the currently handled enter / leave pair
first = std::next(leave);
}
return fn;
}
LaneID inline numLanesToTheRight(const engine::guidance::RouteStep &step)
{
return step.intersections.front().lanes.first_lane_from_the_right;
}
LaneID inline numLanesToTheLeft(const engine::guidance::RouteStep &step)
{
LaneID const total = step.intersections.front().lane_description.size();
return total - (step.intersections.front().lanes.lanes_in_turn +
step.intersections.front().lanes.first_lane_from_the_right);
}
auto inline lanesToTheLeft(const engine::guidance::RouteStep &step)
{
const auto &description = step.intersections.front().lane_description;
LaneID num_lanes_left = numLanesToTheLeft(step);
return boost::make_iterator_range(description.begin(), description.begin() + num_lanes_left);
}
auto inline lanesToTheRight(const engine::guidance::RouteStep &step)
{
const auto &description = step.intersections.front().lane_description;
LaneID num_lanes_right = numLanesToTheRight(step);
return boost::make_iterator_range(description.end() - num_lanes_right, description.end());
}
} // namespace guidance
} // namespace engine
} // namespace osrm
#endif /* OSRM_ENGINE_GUIDANCE_TOOLKIT_HPP_ */
+8 -11
View File
@@ -3,8 +3,8 @@
#include "util/coordinate.hpp"
#include <algorithm>
#include <boost/assert.hpp>
#include <algorithm>
#include <string>
#include <vector>
@@ -13,17 +13,17 @@ namespace osrm
namespace engine
{
namespace detail
{
constexpr double POLYLINE_DECODING_PRECISION = 1e5;
constexpr double POLYLINE_TO_COORDINATE = COORDINATE_PRECISION / POLYLINE_DECODING_PRECISION;
{
constexpr double POLYLINE_DECODING_PRECISION = 1e5;
constexpr double POLYLINE_TO_COORDINATE = COORDINATE_PRECISION / POLYLINE_DECODING_PRECISION;
std::string encode(std::vector<int> &numbers);
}
std::string encode(std::vector<int> &numbers);
}
using CoordVectorForwardIter = std::vector<util::Coordinate>::const_iterator;
// Encodes geometry into polyline format.
// See: https://developers.google.com/maps/documentation/utilities/polylinealgorithm
template <unsigned POLYLINE_PRECISION = 100000>
template<unsigned POLYLINE_PRECISION=100000>
std::string encodePolyline(CoordVectorForwardIter begin, CoordVectorForwardIter end)
{
double coordinate_to_polyline = POLYLINE_PRECISION / COORDINATE_PRECISION;
@@ -39,10 +39,7 @@ std::string encodePolyline(CoordVectorForwardIter begin, CoordVectorForwardIter
int current_lat = 0;
int current_lon = 0;
std::for_each(
begin,
end,
[&delta_numbers, &current_lat, &current_lon, coordinate_to_polyline](
const util::Coordinate loc) {
begin, end, [&delta_numbers, &current_lat, &current_lon, coordinate_to_polyline](const util::Coordinate loc) {
const int lat_diff =
std::round(static_cast<int>(loc.lat) * coordinate_to_polyline) - current_lat;
const int lon_diff =
@@ -235,10 +235,10 @@ class AlternativeRouting final
}
}
// util::Log(logDEBUG) << "fwd_search_space size: " <<
// util::SimpleLogger().Write(logDEBUG) << "fwd_search_space size: " <<
// forward_search_space.size() << ", marked " << approximated_forward_sharing.size() << "
// nodes";
// util::Log(logDEBUG) << "rev_search_space size: " <<
// util::SimpleLogger().Write(logDEBUG) << "rev_search_space size: " <<
// reverse_search_space.size() << ", marked " << approximated_reverse_sharing.size() << "
// nodes";
@@ -601,7 +601,7 @@ class AlternativeRouting final
// //compute forward sharing
// while( (packed_alternate_path[aindex] == packed_shortest_path[aindex]) &&
// (packed_alternate_path[aindex+1] == packed_shortest_path[aindex+1]) ) {
// // util::Log() << "retrieving edge (" <<
// // util::SimpleLogger().Write() << "retrieving edge (" <<
// packed_alternate_path[aindex] << "," << packed_alternate_path[aindex+1] << ")";
// EdgeID edgeID = facade->FindEdgeInEitherDirection(packed_alternate_path[aindex],
// packed_alternate_path[aindex+1]);
@@ -640,7 +640,7 @@ class AlternativeRouting final
const NodeID node = forward_heap.DeleteMin();
const int weight = forward_heap.GetKey(node);
// const NodeID parentnode = forward_heap.GetData(node).parent;
// util::Log() << (is_forward_directed ? "[fwd] " : "[rev] ") << "settled
// util::SimpleLogger().Write() << (is_forward_directed ? "[fwd] " : "[rev] ") << "settled
// edge ("
// << parentnode << "," << node << "), dist: " << weight;
@@ -665,11 +665,11 @@ class AlternativeRouting final
{
*middle_node = node;
*upper_bound_to_shortest_path_weight = new_weight;
// util::Log() << "accepted middle_node " << *middle_node
// util::SimpleLogger().Write() << "accepted middle_node " << *middle_node
// << " at
// weight " << new_weight;
// } else {
// util::Log() << "discarded middle_node " << *middle_node
// util::SimpleLogger().Write() << "discarded middle_node " << *middle_node
// << "
// at weight " << new_weight;
}
+1 -1
View File
@@ -2,7 +2,7 @@
#define TRIP_BRUTE_FORCE_HPP
#include "util/dist_table_wrapper.hpp"
#include "util/log.hpp"
#include "util/simple_logger.hpp"
#include "util/typedefs.hpp"
#include "osrm/json_container.hpp"
@@ -3,6 +3,7 @@
#include "util/dist_table_wrapper.hpp"
#include "util/typedefs.hpp"
#include "util/typedefs.hpp"
#include "osrm/json_container.hpp"
#include <boost/assert.hpp>
@@ -2,7 +2,7 @@
#define TRIP_NEAREST_NEIGHBOUR_HPP
#include "util/dist_table_wrapper.hpp"
#include "util/log.hpp"
#include "util/simple_logger.hpp"
#include "util/typedefs.hpp"
#include "osrm/json_container.hpp"
+13 -7
View File
@@ -3,7 +3,6 @@
#include "extractor/travel_mode.hpp"
#include "util/typedefs.hpp"
#include <tuple>
namespace osrm
{
@@ -61,12 +60,19 @@ inline EdgeBasedEdge::EdgeBasedEdge(const NodeID source,
inline bool EdgeBasedEdge::operator<(const EdgeBasedEdge &other) const
{
const auto unidirectional = (!forward || !backward);
const auto other_is_unidirectional = (!other.forward || !other.backward);
// if all items are the same, we want to keep bidirectional edges. due to the `<` operator,
// preferring 0 (false) over 1 (true), we need to compare the inverse of `bidirectional`
return std::tie(source, target, weight, unidirectional) <
std::tie(other.source, other.target, other.weight, other_is_unidirectional);
if (source == other.source)
{
if (target == other.target)
{
if (weight == other.weight)
{
return forward && backward && ((!other.forward) || (!other.backward));
}
return weight < other.weight;
}
return target < other.target;
}
return source < other.source;
}
} // ns extractor
} // ns osrm
@@ -29,6 +29,7 @@
#include <memory>
#include <queue>
#include <string>
#include <string>
#include <unordered_map>
#include <unordered_set>
#include <vector>
@@ -32,7 +32,6 @@ class ExtractionContainers
#else
const static unsigned stxxl_memory = ((sizeof(std::size_t) == 4) ? INT_MAX : UINT_MAX);
#endif
void FlushVectors();
void PrepareNodes();
void PrepareRestrictions();
void PrepareEdges(ScriptingEnvironment &scripting_environment);
@@ -12,7 +12,7 @@
#include <limits>
#include <string>
#include "extractor/guidance/parsing_toolkit.hpp"
#include "extractor/guidance/toolkit.hpp"
namespace osrm
{
@@ -109,13 +109,13 @@ inline unsigned parseDuration(const std::string &s)
inline std::string
trimLaneString(std::string lane_string, std::int32_t count_left, std::int32_t count_right)
{
return guidance::trimLaneString(std::move(lane_string), count_left, count_right);
return extractor::guidance::trimLaneString(std::move(lane_string), count_left, count_right);
}
inline std::string applyAccessTokens(const std::string &lane_string,
const std::string &access_tokens)
{
return guidance::applyAccessTokens(lane_string, access_tokens);
return extractor::guidance::applyAccessTokens(lane_string, access_tokens);
}
// Takes a string representing a list separated by delim and canonicalizes containing spaces.
+2 -36
View File
@@ -13,20 +13,6 @@ namespace osrm
{
namespace extractor
{
namespace detail
{
inline void maybeSetString(std::string &str, const char *value)
{
if (value == nullptr)
{
str.clear();
}
else
{
str = std::string(value);
}
}
}
/**
* This struct is the direct result of the call to ```way_function```
@@ -44,8 +30,8 @@ struct ExtractionWay
backward_speed = -1;
duration = -1;
roundabout = false;
circular = false;
is_startpoint = true;
is_access_restricted = false;
name.clear();
ref.clear();
pronunciation.clear();
@@ -64,26 +50,6 @@ struct ExtractionWay
void set_backward_mode(const TravelMode m) { backward_travel_mode = m; }
TravelMode get_backward_mode() const { return backward_travel_mode; }
// wrappers to allow assigning nil (nullptr) to string values
void SetName(const char *value) { detail::maybeSetString(name, value); }
const char *GetName() const { return name.c_str(); }
void SetRef(const char *value) { detail::maybeSetString(ref, value); }
const char *GetRef() const { return ref.c_str(); }
void SetDestinations(const char *value) { detail::maybeSetString(destinations, value); }
const char *GetDestinations() const { return destinations.c_str(); }
void SetPronunciation(const char *value) { detail::maybeSetString(pronunciation, value); }
const char *GetPronunciation() const { return pronunciation.c_str(); }
void SetTurnLanesForward(const char *value)
{
detail::maybeSetString(turn_lanes_forward, value);
}
const char *GetTurnLanesForward() const { return turn_lanes_forward.c_str(); }
void SetTurnLanesBackward(const char *value)
{
detail::maybeSetString(turn_lanes_backward, value);
}
const char *GetTurnLanesBackward() const { return turn_lanes_backward.c_str(); }
double forward_speed;
double backward_speed;
double duration;
@@ -94,7 +60,7 @@ struct ExtractionWay
std::string turn_lanes_forward;
std::string turn_lanes_backward;
bool roundabout;
bool circular;
bool is_access_restricted;
bool is_startpoint;
TravelMode forward_travel_mode : 4;
TravelMode backward_travel_mode : 4;
+1 -2
View File
@@ -11,8 +11,7 @@
#include "extractor/guidance/coordinate_extractor.hpp"
#include "extractor/guidance/intersection.hpp"
#include <boost/optional.hpp>
#include "extractor/guidance/toolkit.hpp"
namespace osrm
{
@@ -1,14 +1,13 @@
#ifndef OSRM_EXTRACTOR_COORDINATE_EXTRACTOR_HPP_
#define OSRM_EXTRACTOR_COORDINATE_EXTRACTOR_HPP_
#include <utility>
#include <vector>
#include "extractor/compressed_edge_container.hpp"
#include "extractor/query_node.hpp"
#include "util/attributes.hpp"
#include "util/coordinate.hpp"
#include "util/coordinate_calculation.hpp"
#include "extractor/compressed_edge_container.hpp"
#include "util/node_based_graph.hpp"
namespace osrm
@@ -28,51 +27,24 @@ class CoordinateExtractor
/* Find a interpolated coordinate a long the compressed geometries. The desired coordinate
* should be in a certain distance. This method is dedicated to find representative coordinates
* at turns.
* Since we are computing the length of the segment anyhow, we also return it.
*/
OSRM_ATTR_WARN_UNUSED
util::Coordinate GetCoordinateAlongRoad(const NodeID intersection_node,
const EdgeID turn_edge,
const bool traversed_in_reverse,
const NodeID to_node,
const std::uint8_t number_of_in_lanes) const;
// Given a set of precomputed coordinates, select the representative coordinate along the road
// that best describes the turn
OSRM_ATTR_WARN_UNUSED
util::Coordinate
ExtractRepresentativeCoordinate(const NodeID intersection_node,
const EdgeID turn_edge,
const bool traversed_in_reverse,
const NodeID to_node,
const std::uint8_t intersection_lanes,
std::vector<util::Coordinate> coordinates) const;
// instead of finding only a single coordinate, we can also list all coordinates along a
// road.
OSRM_ATTR_WARN_UNUSED std::vector<util::Coordinate>
GetCoordinatesAlongRoad(const NodeID intersection_node,
const EdgeID turn_edge,
const bool traversed_in_reverse,
const NodeID to_node) const;
// instead of finding only a single coordinate, we can also list all coordinates along a road.
std::vector<util::Coordinate> GetCoordinatesAlongRoad(const NodeID intersection_node,
const EdgeID turn_edge,
const bool traversed_in_reverse,
const NodeID to_node) const;
// wrapper in case of normal forward edges (traversed_in_reverse = false, to_node =
// node_based_graph.GetTarget(turn_edge)
OSRM_ATTR_WARN_UNUSED
std::vector<util::Coordinate> GetForwardCoordinatesAlongRoad(const NodeID from,
const EdgeID turn_edge) const;
// a less precise way to compute coordinates along a route. Due to the heavy interaction of
// graph traversal and turn instructions, we often don't care for high precision. We only want
// to check for available connections in order, or find (with room for error) the straightmost
// turn. This function will offer a bit more error potential but allow for much higher
// performance
OSRM_ATTR_WARN_UNUSED
util::Coordinate GetCoordinateCloseToTurn(const NodeID from_node,
const EdgeID turn_edge,
const bool traversed_in_reverse,
const NodeID to_node) const;
/* When extracting the coordinates, we first extract all coordinates. We don't care about most
* of them, though.
*
@@ -89,25 +61,14 @@ class CoordinateExtractor
* For calculating the turn angle for the intersection at `a`, we do not care about the turn
* between `v` and `b`. This calculation trims the coordinates to the ones immediately at the
* intersection.
*
* The optional length cache needs to store the accumulated distance up to the respective
* coordinate index [0,d(0,1),...]
*/
OSRM_ATTR_WARN_UNUSED
std::vector<util::Coordinate>
TrimCoordinatesToLength(std::vector<util::Coordinate> coordinates,
const double desired_length,
const std::vector<double> &length_cache = {}) const;
OSRM_ATTR_WARN_UNUSED
std::vector<double> PrepareLengthCache(const std::vector<util::Coordinate> &coordinates,
const double limit) const;
std::vector<util::Coordinate> TrimCoordinatesToLength(std::vector<util::Coordinate> coordinates,
const double desired_length) const;
/* when looking at a set of coordinates, this function allows trimming the vector to a smaller,
* only containing coordinates up to a given distance along the path. The last coordinate might
* be interpolated
*/
OSRM_ATTR_WARN_UNUSED
std::vector<util::Coordinate>
TrimCoordinatesByLengthFront(std::vector<util::Coordinate> coordinates,
const double desired_length) const;
@@ -133,7 +94,6 @@ class CoordinateExtractor
*
* for fixpoint `b`, vector_base `d` and vector_head `e`
*/
OSRM_ATTR_WARN_UNUSED
util::Coordinate GetCorrectedCoordinate(const util::Coordinate fixpoint,
const util::Coordinate vector_base,
const util::Coordinate vector_head) const;
@@ -146,7 +106,6 @@ class CoordinateExtractor
* Into:
* x -- x -- x -- x -- x - x
*/
OSRM_ATTR_WARN_UNUSED
std::vector<util::Coordinate>
SampleCoordinates(const std::vector<util::Coordinate> &coordinates,
const double length,
@@ -240,14 +199,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
+40 -163
View File
@@ -1,23 +1,14 @@
#ifndef OSRM_EXTRACTOR_GUIDANCE_INTERSECTION_HPP_
#define OSRM_EXTRACTOR_GUIDANCE_INTERSECTION_HPP_
#include <algorithm>
#include <functional>
#include <limits>
#include <string>
#include <type_traits>
#include <vector>
#include "extractor/guidance/turn_instruction.hpp"
#include "util/bearing.hpp"
#include "util/guidance/toolkit.hpp"
#include "util/node_based_graph.hpp"
#include "util/typedefs.hpp" // EdgeID
#include <boost/range/adaptor/transformed.hpp>
#include <boost/range/algorithm/find_if.hpp>
#include <boost/assert.hpp>
namespace osrm
{
namespace extractor
@@ -25,50 +16,22 @@ namespace extractor
namespace guidance
{
// the shape of an intersection only knows about edge IDs and bearings
struct IntersectionShapeData
// Every Turn Operation describes a way of switching onto a segment, indicated by an EdgeID. The
// associated turn is described by an angle and an instruction that is used to announce it.
// The Turn Operation indicates what is exposed to the outside of the turn analysis.
struct TurnOperation
{
EdgeID eid;
double bearing;
double segment_length;
};
inline auto makeCompareShapeDataByBearing(const double base_bearing)
{
return [base_bearing](const auto &lhs, const auto &rhs) {
return util::angleBetweenBearings(base_bearing, lhs.bearing) <
util::angleBetweenBearings(base_bearing, rhs.bearing);
};
}
inline auto makeCompareAngularDeviation(const double angle)
{
return [angle](const auto &lhs, const auto &rhs) {
return util::angularDeviation(lhs.angle, angle) < util::angularDeviation(rhs.angle, angle);
};
}
// When viewing an intersection from an incoming edge, we can transform a shape into a view which
// gives additional information on angles and whether a turn is allowed
struct IntersectionViewData : IntersectionShapeData
{
IntersectionViewData(const IntersectionShapeData &shape,
const bool entry_allowed,
const double angle)
: IntersectionShapeData(shape), entry_allowed(entry_allowed), angle(angle)
{
}
bool entry_allowed;
double angle;
bool CompareByAngle(const IntersectionViewData &other) const;
double bearing;
TurnInstruction instruction;
LaneDataID lane_data_id;
};
// A Connected Road is the internal representation of a potential turn. Internally, we require
// full list of all connected roads to determine the outcome.
// The reasoning behind is that even invalid turns can influence the perceived angles, or even
// instructions themselves. An possible example can be described like this:
// instructions themselves. An pososible example can be described like this:
//
// aaa(2)aa
// a - bbbbb
@@ -76,7 +39,8 @@ struct IntersectionViewData : IntersectionShapeData
//
// will not be perceived as a turn from (1) -> b, and as a U-turn from (1) -> (2).
// In addition, they can influence whether a turn is obvious or not. b->(2) would also be no
// turn-operation, but rather a name change.
// turn-operation,
// but rather a name change.
//
// If this were a normal intersection with
//
@@ -85,17 +49,14 @@ struct IntersectionViewData : IntersectionShapeData
// aaaaaaaa
//
// We would perceive a->c as a sharp turn, a->b as a slight turn, and b->c as a slight turn.
struct ConnectedRoad final : IntersectionViewData
struct ConnectedRoad final : public TurnOperation
{
ConnectedRoad(const IntersectionViewData &view,
const TurnInstruction instruction,
const LaneDataID lane_data_id)
: IntersectionViewData(view), instruction(instruction), lane_data_id(lane_data_id)
{
}
using Base = TurnOperation;
TurnInstruction instruction;
LaneDataID lane_data_id;
ConnectedRoad(const TurnOperation turn, const bool entry_allowed = false);
// a turn may be relevant to good instructions, even if we cannot enter the road
bool entry_allowed;
// used to sort the set of connected roads (we require sorting throughout turn handling)
bool compareByAngle(const ConnectedRoad &other) const;
@@ -110,117 +71,33 @@ struct ConnectedRoad final : IntersectionViewData
// small helper function to print the content of a connected road
std::string toString(const ConnectedRoad &road);
// Intersections are sorted roads: [0] being the UTurn road, then from sharp right to sharp left.
using IntersectionShape = std::vector<IntersectionShapeData>;
// Common operations shared among IntersectionView and Intersections.
// Inherit to enable those operations on your compatible type. CRTP pattern.
template <typename Self> struct EnableIntersectionOps
{
// Find the turn whose angle offers the least angular deviation to the specified angle
// For turn angles [0, 90, 260] and a query of 180 we return the 260 degree turn.
auto findClosestTurn(double angle) const
{
auto comp = makeCompareAngularDeviation(angle);
return std::min_element(self()->begin(), self()->end(), comp);
}
// Check validity of the intersection object. We assume a few basic properties every set of
// connected roads should follow throughout guidance pre-processing. This utility function
// allows checking intersections for validity
auto valid() const
{
if (self()->empty())
return false;
auto comp = [](const auto &lhs, const auto &rhs) { return lhs.CompareByAngle(rhs); };
const auto ordered = std::is_sorted(self()->begin(), self()->end(), comp);
if (!ordered)
return false;
const auto uturn = self()->operator[](0).angle < std::numeric_limits<double>::epsilon();
if (!uturn)
return false;
return true;
}
// Given all possible turns which is the highest connected number of lanes per turn.
// This value is used for example during generation of intersections.
auto getHighestConnectedLaneCount(const util::NodeBasedDynamicGraph &graph) const
{
const std::function<std::uint8_t(const ConnectedRoad &)> to_lane_count =
[&](const ConnectedRoad &road) {
return graph.GetEdgeData(road.eid).road_classification.GetNumberOfLanes();
};
std::uint8_t max_lanes = 0;
const auto extract_maximal_value = [&max_lanes](std::uint8_t value) {
max_lanes = std::max(max_lanes, value);
return false;
};
const auto view = *self() | boost::adaptors::transformed(to_lane_count);
boost::range::find_if(view, extract_maximal_value);
return max_lanes;
}
// Returns the UTurn road we took to arrive at this intersection.
const auto &getUTurnRoad() const { return self()->operator[](0); }
// Returns the right-most road at this intersection.
const auto &getRightmostRoad() const
{
return self()->size() > 1 ? self()->operator[](1) : self()->getUTurnRoad();
}
// Returns the left-most road at this intersection.
const auto &getLeftmostRoad() const
{
return self()->size() > 1 ? self()->back() : self()->getUTurnRoad();
}
// Can this be skipped over?
auto isTrafficSignalOrBarrier() const { return self()->size() == 2; }
// Checks if there is at least one road available (except UTurn road) on which to continue.
auto isDeadEnd() const
{
auto pred = [](const auto &road) { return road.entry_allowed; };
return !std::any_of(self()->begin() + 1, self()->end(), pred);
}
// Returns the number of roads we can enter at this intersection, respectively.
auto countEnterable() const
{
auto pred = [](const auto &road) { return road.entry_allowed; };
return std::count_if(self()->begin(), self()->end(), pred);
}
// Returns the number of roads we can not enter at this intersection, respectively.
auto countNonEnterable() const { return self()->size() - self()->countEnterable(); }
private:
auto self() { return static_cast<Self *>(this); }
auto self() const { return static_cast<const Self *>(this); }
};
struct IntersectionView final : std::vector<IntersectionViewData>, //
EnableIntersectionOps<IntersectionView> //
{
using Base = std::vector<IntersectionViewData>;
};
struct Intersection final : std::vector<ConnectedRoad>, //
EnableIntersectionOps<Intersection> //
struct Intersection final : public std::vector<ConnectedRoad>
{
using Base = std::vector<ConnectedRoad>;
/*
* find the turn whose angle offers the least angularDeviation to the specified angle
* E.g. for turn angles [0,90,260] and a query of 180 we return the 260 degree turn (difference
* 80 over the difference of 90 to the 90 degree turn)
*/
Base::iterator findClosestTurn(double angle);
Base::const_iterator findClosestTurn(double angle) const;
/*
* Check validity of the intersection object. We assume a few basic properties every set of
* connected roads should follow throughout guidance pre-processing. This utility function
* allows checking intersections for validity
*/
bool valid() const;
// given all possible turns, which is the highest connected number of lanes per turn. This value
// is used, for example, during generation of intersections.
std::uint8_t getHighestConnectedLaneCount(const util::NodeBasedDynamicGraph &) const;
};
Intersection::const_iterator findClosestTurn(const Intersection &intersection, const double angle);
Intersection::iterator findClosestTurn(Intersection &intersection, const double angle);
} // namespace guidance
} // namespace extractor
} // namespace osrm
@@ -6,16 +6,15 @@
#include "extractor/guidance/intersection.hpp"
#include "extractor/query_node.hpp"
#include "extractor/restriction_map.hpp"
#include "extractor/suffix_table.hpp"
#include "util/attributes.hpp"
#include "util/name_table.hpp"
#include "util/node_based_graph.hpp"
#include "util/typedefs.hpp"
#include <unordered_set>
#include <utility>
#include <vector>
#include <boost/optional.hpp>
namespace osrm
{
namespace extractor
@@ -26,6 +25,7 @@ namespace guidance
// from it. For this all turn possibilities are analysed.
// We consider turn restrictions to indicate possible turns. U-turns are generated based on profile
// decisions.
class IntersectionGenerator
{
public:
@@ -33,89 +33,80 @@ class IntersectionGenerator
const RestrictionMap &restriction_map,
const std::unordered_set<NodeID> &barrier_nodes,
const std::vector<QueryNode> &node_info_list,
const CompressedEdgeContainer &compressed_edge_container);
const CompressedEdgeContainer &compressed_edge_container,
const util::NameTable &name_table,
const SuffixTable &street_name_suffix_table);
// For a source node `a` and a via edge `ab` creates an intersection at target `b`.
//
// a . . . b . .
// .
// .
//
IntersectionView operator()(const NodeID nid, const EdgeID via_eid) const;
/*
* Compute the shape of an intersection, returning a set of connected roads, without any further
* concern for which of the entries are actually allowed.
* The shape also only comes with turn bearings, not with turn angles. All turn angles will be
* set to zero
*/
OSRM_ATTR_WARN_UNUSED
IntersectionShape
ComputeIntersectionShape(const NodeID center_node,
const boost::optional<NodeID> sorting_base = boost::none,
bool use_low_precision_angles = false) const;
Intersection operator()(const NodeID nid, const EdgeID via_eid) const;
// Graph Compression cannot compress every setting. For example any barrier/traffic light cannot
// be compressed. As a result, a simple road of the form `a ----- b` might end up as having an
// intermediate intersection, if there is a traffic light in between. If we want to look farther
// down a road, finding the next actual decision requires the look at multiple intersections.
// Here we follow the road until we either reach a dead end or find the next intersection with
// more than a single next road. This function skips over degree two nodes to find coorect input
// for GetConnectedRoads.
OSRM_ATTR_WARN_UNUSED
std::pair<NodeID, EdgeID> SkipDegreeTwoNodes(const NodeID starting_node,
const EdgeID via_edge) const;
// more than a single next road.
Intersection GetActualNextIntersection(const NodeID starting_node,
const EdgeID via_edge,
NodeID *resulting_from_node,
EdgeID *resulting_via_edge) const;
// Allow access to the coordinate extractor for all owners
const CoordinateExtractor &GetCoordinateExtractor() const;
// Check for restrictions/barriers and generate a list of valid and invalid turns present at
// the node reached from `from_node` via `via_eid`. The resulting candidates have to be analysed
// for their actual instructions later on.
// The switch for `use_low_precision_angles` enables a faster mode that will procude less
// accurate coordinates. It should be good enough to check order of turns, find striaghtmost
// turns. Even good enough to do some simple angle verifications. It is mostly available to
// allow for faster graph traversal in the extraction phase.
// the
// node reached
// from `from_node` via `via_eid`
// The resulting candidates have to be analysed for their actual instructions later on.
OSRM_ATTR_WARN_UNUSED
IntersectionView GetConnectedRoads(const NodeID from_node,
const EdgeID via_eid,
const bool use_low_precision_angles = false) const;
/*
* To be used in the road network, we need to check for valid/restricted turns. These two
* functions transform a basic intersection / a normalised intersection into the
* correct view when entering via a given edge.
*/
OSRM_ATTR_WARN_UNUSED
IntersectionView
TransformIntersectionShapeIntoView(const NodeID previous_node,
const EdgeID entering_via_edge,
const IntersectionShape &intersection) const;
// version for normalised intersection
OSRM_ATTR_WARN_UNUSED
IntersectionView TransformIntersectionShapeIntoView(
const NodeID previous_node,
const EdgeID entering_via_edge,
const IntersectionShape &normalised_intersection,
const IntersectionShape &intersection,
const std::vector<std::pair<EdgeID, EdgeID>> &merging_map) const;
Intersection GetConnectedRoads(const NodeID from_node, const EdgeID via_eid) const;
private:
const util::NodeBasedDynamicGraph &node_based_graph;
const RestrictionMap &restriction_map;
const std::unordered_set<NodeID> &barrier_nodes;
const std::vector<QueryNode> &node_info_list;
// own state, used to find the correct coordinates along a road
const CoordinateExtractor coordinate_extractor;
const util::NameTable &name_table;
const SuffixTable &street_name_suffix_table;
// check turn restrictions to find a node that is the only allowed target when coming from a
// node to an intersection
// d
// |
// a - b - c and `only_straight_on ab | bc would return `c` for `a,b`
boost::optional<NodeID> GetOnlyAllowedTurnIfExistent(const NodeID coming_from_node,
const NodeID node_at_intersection) const;
// check if two indices in an intersection can be seen as a single road in the perceived
// intersection representation. See below for an example. Utility function for
// MergeSegregatedRoads
bool CanMerge(const NodeID intersection_node,
const Intersection &intersection,
std::size_t first_index,
std::size_t second_index) const;
// Merge segregated roads to omit invalid turns in favor of treating segregated roads as
// one.
// This function combines roads the following way:
//
// * *
// * is converted to *
// v ^ +
// v ^ +
//
// The treatment results in a straight turn angle of 180º rather than a turn angle of approx
// 160
OSRM_ATTR_WARN_UNUSED
Intersection MergeSegregatedRoads(const NodeID intersection_node,
Intersection intersection) const;
// The counterpiece to mergeSegregatedRoads. While we can adjust roads that split up at the
// intersection itself, it can also happen that intersections are connected to joining roads.
//
// * *
// * is converted to *
// v a --- a ---
// v ^ +
// v ^ +
// b
//
// for the local view of b at a.
OSRM_ATTR_WARN_UNUSED
Intersection AdjustForJoiningRoads(const NodeID node_at_intersection,
Intersection intersection) const;
};
} // namespace guidance
@@ -3,22 +3,15 @@
#include "extractor/guidance/intersection.hpp"
#include "extractor/guidance/intersection_generator.hpp"
#include "extractor/guidance/node_based_graph_walker.hpp"
#include "extractor/query_node.hpp"
#include "extractor/suffix_table.hpp"
#include "util/coordinate_calculation.hpp"
#include "util/guidance/name_announcements.hpp"
#include "util/name_table.hpp"
#include "util/node_based_graph.hpp"
#include <algorithm>
#include <cstddef>
#include <utility>
#include <vector>
#include <boost/optional.hpp>
namespace osrm
{
namespace extractor
@@ -55,7 +48,9 @@ class IntersectionHandler
const util::NameTable &name_table;
const SuffixTable &street_name_suffix_table;
const IntersectionGenerator &intersection_generator;
const NodeBasedGraphWalker graph_walker; // for skipping traffic signal, distances etc.
// counts the number on allowed entry roads
std::size_t countValid(const Intersection &intersection) const;
// Decide on a basic turn types
TurnType::Enum findBasicTurnType(const EdgeID via_edge, const ConnectedRoad &candidate) const;
@@ -64,8 +59,7 @@ class IntersectionHandler
// determining whether there is a road that can be seen as obvious turn in the presence of many
// other possible turns. The function will consider road categories and other inputs like the
// turn angles.
template <typename IntersectionType> // works with Intersection and IntersectionView
std::size_t findObviousTurn(const EdgeID via_edge, const IntersectionType &intersection) const;
std::size_t findObviousTurn(const EdgeID via_edge, const Intersection &intersection) const;
// Obvious turns can still take multiple forms. This function looks at the turn onto a road
// candidate when coming from a via_edge and determines the best instruction to emit.
@@ -89,458 +83,9 @@ class IntersectionHandler
const std::size_t begin,
const std::size_t end) const;
// Checks the intersection for a through street connected to `intersection[index]`
bool isThroughStreet(const std::size_t index, const Intersection &intersection) const;
// See `getNextIntersection`
struct IntersectionViewAndNode final
{
IntersectionView intersection; // < actual intersection
NodeID node; // < node at this intersection
};
// Skips over artificial intersections i.e. traffic lights, barriers etc.
// Returns the next non-artificial intersection and its node in the node based
// graph if an intersection could be found or none otherwise.
//
// a ... tl ... b .. c
// .
// .
// d
//
// ^ at
// ^ via
//
// For this scenario returns intersection at `b` and `b`.
boost::optional<IntersectionHandler::IntersectionViewAndNode>
getNextIntersection(const NodeID at, const EdgeID via) const;
};
// Impl.
template <typename IntersectionType> // works with Intersection and IntersectionView
std::size_t IntersectionHandler::findObviousTurn(const EdgeID via_edge,
const IntersectionType &intersection) const
{
using Road = typename IntersectionType::value_type;
using EdgeData = osrm::util::NodeBasedDynamicGraph::EdgeData;
using osrm::util::angularDeviation;
// no obvious road
if (intersection.size() == 1)
return 0;
// a single non u-turn is obvious
if (intersection.size() == 2)
return 1;
const EdgeData &in_way_data = node_based_graph.GetEdgeData(via_edge);
// the strategy for picking the most obvious turn involves deciding between
// an overall best candidate and a best candidate that shares the same name
// as the in road, i.e. a continue road
std::size_t best_option = 0;
double best_option_deviation = 180;
std::size_t best_continue = 0;
double best_continue_deviation = 180;
/* helper functions */
const auto IsContinueRoad = [&](const EdgeData &way_data) {
return !util::guidance::requiresNameAnnounced(
in_way_data.name_id, way_data.name_id, name_table, street_name_suffix_table);
};
auto sameOrHigherPriority = [&in_way_data](const auto &way_data) {
return way_data.road_classification.GetPriority() <=
in_way_data.road_classification.GetPriority();
};
auto IsLowPriority = [](const auto &way_data) {
return way_data.road_classification.IsLowPriorityRoadClass();
};
// These two Compare functions are used for sifting out best option and continue
// candidates by evaluating all the ways in an intersection by what they share
// with the in way. Ideal candidates are of similar road class with the in way
// and are require relatively straight turns.
const auto RoadCompare = [&](const auto &lhs, const auto &rhs) {
const EdgeData &lhs_data = node_based_graph.GetEdgeData(lhs.eid);
const EdgeData &rhs_data = node_based_graph.GetEdgeData(rhs.eid);
const auto lhs_deviation = angularDeviation(lhs.angle, STRAIGHT_ANGLE);
const auto rhs_deviation = angularDeviation(rhs.angle, STRAIGHT_ANGLE);
const bool rhs_same_classification =
rhs_data.road_classification == in_way_data.road_classification;
const bool lhs_same_classification =
lhs_data.road_classification == in_way_data.road_classification;
const bool rhs_same_or_higher_priority = sameOrHigherPriority(rhs_data);
const bool rhs_low_priority = IsLowPriority(rhs_data);
const bool lhs_same_or_higher_priority = sameOrHigherPriority(lhs_data);
const bool lhs_low_priority = IsLowPriority(lhs_data);
auto left_tie = std::tie(lhs.entry_allowed,
lhs_same_or_higher_priority,
rhs_low_priority,
rhs_deviation,
lhs_same_classification);
auto right_tie = std::tie(rhs.entry_allowed,
rhs_same_or_higher_priority,
lhs_low_priority,
lhs_deviation,
rhs_same_classification);
return left_tie > right_tie;
};
const auto RoadCompareSameName = [&](const auto &lhs, const auto &rhs) {
const EdgeData &lhs_data = node_based_graph.GetEdgeData(lhs.eid);
const EdgeData &rhs_data = node_based_graph.GetEdgeData(rhs.eid);
const auto lhs_continues = IsContinueRoad(lhs_data);
const auto rhs_continues = IsContinueRoad(rhs_data);
const auto left_tie = std::tie(lhs.entry_allowed, lhs_continues);
const auto right_tie = std::tie(rhs.entry_allowed, rhs_continues);
return left_tie > right_tie || (left_tie == right_tie && RoadCompare(lhs, rhs));
};
auto best_option_it = std::min_element(begin(intersection), end(intersection), RoadCompare);
// min element should only return end() when vector is empty
BOOST_ASSERT(best_option_it != end(intersection));
best_option = std::distance(begin(intersection), best_option_it);
best_option_deviation = angularDeviation(intersection[best_option].angle, STRAIGHT_ANGLE);
const auto &best_option_data = node_based_graph.GetEdgeData(intersection[best_option].eid);
// Unless the in way is also low priority, it is generally undesirable to
// indicate that a low priority road is obvious
if (IsLowPriority(best_option_data) &&
best_option_data.road_classification != in_way_data.road_classification)
{
best_option = 0;
best_option_deviation = 180;
}
// double check if the way with the lowest deviation from straight is still be better choice
const auto straightest = intersection.findClosestTurn(STRAIGHT_ANGLE);
if (straightest != best_option_it)
{
const EdgeData &straightest_data = node_based_graph.GetEdgeData(straightest->eid);
double straightest_data_deviation = angularDeviation(straightest->angle, STRAIGHT_ANGLE);
const auto deviation_diff =
std::abs(best_option_deviation - straightest_data_deviation) > FUZZY_ANGLE_DIFFERENCE;
const auto not_ramp_class = !straightest_data.road_classification.IsRampClass();
const auto not_link_class = !straightest_data.road_classification.IsLinkClass();
if (deviation_diff && !IsLowPriority(straightest_data) && not_ramp_class &&
not_link_class && !IsContinueRoad(best_option_data))
{
best_option = std::distance(begin(intersection), straightest);
best_option_deviation =
angularDeviation(intersection[best_option].angle, STRAIGHT_ANGLE);
}
}
// No non-low priority roads? Declare no obvious turn
if (best_option == 0)
return 0;
auto best_continue_it =
std::min_element(begin(intersection), end(intersection), RoadCompareSameName);
const auto best_continue_data = node_based_graph.GetEdgeData(best_continue_it->eid);
if (IsContinueRoad(best_continue_data) ||
(in_way_data.name_id == EMPTY_NAMEID && best_continue_data.name_id == EMPTY_NAMEID))
{
best_continue = std::distance(begin(intersection), best_continue_it);
best_continue_deviation =
angularDeviation(intersection[best_continue].angle, STRAIGHT_ANGLE);
}
// if the best angle is going straight but the road is turning, declare no obvious turn
if (0 != best_continue && best_option != best_continue &&
best_option_deviation < MAXIMAL_ALLOWED_NO_TURN_DEVIATION &&
node_based_graph.GetEdgeData(intersection[best_continue].eid).road_classification ==
best_option_data.road_classification)
{
return 0;
}
// get a count of number of ways from that intersection that qualify to have
// continue instruction because they share a name with the approaching way
const std::int64_t continue_count =
count_if(++begin(intersection), end(intersection), [&](const auto &way) {
return IsContinueRoad(node_based_graph.GetEdgeData(way.eid));
});
const std::int64_t continue_count_valid =
count_if(++begin(intersection), end(intersection), [&](const auto &way) {
return IsContinueRoad(node_based_graph.GetEdgeData(way.eid)) && way.entry_allowed;
});
// checks if continue candidates are sharp turns
const bool all_continues_are_narrow = [&]() {
return std::count_if(begin(intersection), end(intersection), [&](const Road &road) {
const EdgeData &road_data = node_based_graph.GetEdgeData(road.eid);
const double &road_angle = angularDeviation(road.angle, STRAIGHT_ANGLE);
return IsContinueRoad(road_data) && (road_angle < NARROW_TURN_ANGLE);
}) == continue_count;
}();
// return true if the best_option candidate is more promising than the best_continue candidate
// otherwise return false, the best_continue candidate is more promising
const auto best_over_best_continue = [&]() {
// no continue road exists
if (best_continue == 0)
return true;
// we have multiple continues and not all are narrow. This suggests that
// the continue candidates are ambiguous
if (!all_continues_are_narrow && (continue_count >= 2 && intersection.size() >= 4))
return true;
// if the best continue is not narrow and we also have at least 2 possible choices, the
// intersection size does not matter anymore
if (continue_count_valid >= 2 && best_continue_deviation >= 2 * NARROW_TURN_ANGLE)
return true;
// continue data now most certainly exists
const auto &continue_data = node_based_graph.GetEdgeData(intersection[best_continue].eid);
// best_continue is obvious by road class
if (obviousByRoadClass(in_way_data.road_classification,
continue_data.road_classification,
best_option_data.road_classification))
return false;
// best_option is obvious by road class
if (obviousByRoadClass(in_way_data.road_classification,
best_option_data.road_classification,
continue_data.road_classification))
return true;
// the best_option deviation is very straight and not a ramp
if (best_option_deviation < best_continue_deviation &&
best_option_deviation < FUZZY_ANGLE_DIFFERENCE &&
!best_option_data.road_classification.IsRampClass())
return true;
// the continue road is of a lower priority, while the road continues on the same priority
// with a better angle
if (best_option_deviation < best_continue_deviation &&
in_way_data.road_classification == best_option_data.road_classification &&
continue_data.road_classification.GetPriority() >
best_option_data.road_classification.GetPriority())
return true;
return false;
}();
if (best_over_best_continue)
{
// Find left/right deviation
// skipping over service roads
const std::size_t left_index = [&]() {
const auto index_candidate = (best_option + 1) % intersection.size();
if (index_candidate == 0)
return index_candidate;
const auto &candidate_data =
node_based_graph.GetEdgeData(intersection[index_candidate].eid);
if (obviousByRoadClass(in_way_data.road_classification,
best_option_data.road_classification,
candidate_data.road_classification))
return (index_candidate + 1) % intersection.size();
else
return index_candidate;
}();
const auto right_index = [&]() {
BOOST_ASSERT(best_option > 0);
const auto index_candidate = best_option - 1;
if (index_candidate == 0)
return index_candidate;
const auto candidate_data =
node_based_graph.GetEdgeData(intersection[index_candidate].eid);
if (obviousByRoadClass(in_way_data.road_classification,
best_option_data.road_classification,
candidate_data.road_classification))
return index_candidate - 1;
else
return index_candidate;
}();
const double left_deviation =
angularDeviation(intersection[left_index].angle, STRAIGHT_ANGLE);
const double right_deviation =
angularDeviation(intersection[right_index].angle, STRAIGHT_ANGLE);
// return best_option candidate if it is nearly straight and distinct from the nearest other
// out
// way
if (best_option_deviation < MAXIMAL_ALLOWED_NO_TURN_DEVIATION &&
std::min(left_deviation, right_deviation) > FUZZY_ANGLE_DIFFERENCE)
return best_option;
const auto &left_data = node_based_graph.GetEdgeData(intersection[left_index].eid);
const auto &right_data = node_based_graph.GetEdgeData(intersection[right_index].eid);
const bool obvious_to_left =
left_index == 0 || obviousByRoadClass(in_way_data.road_classification,
best_option_data.road_classification,
left_data.road_classification);
const bool obvious_to_right =
right_index == 0 || obviousByRoadClass(in_way_data.road_classification,
best_option_data.road_classification,
right_data.road_classification);
// if the best_option turn isn't narrow, but there is a nearly straight turn, we don't
// consider the
// turn obvious
const auto check_narrow = [&intersection, best_option_deviation](const std::size_t index) {
return angularDeviation(intersection[index].angle, STRAIGHT_ANGLE) <=
FUZZY_ANGLE_DIFFERENCE &&
(best_option_deviation > NARROW_TURN_ANGLE || intersection[index].entry_allowed);
};
// other narrow turns?
if (check_narrow(right_index) && !obvious_to_right)
return 0;
if (check_narrow(left_index) && !obvious_to_left)
return 0;
// checks if a given way in the intersection is distinct enough from the best_option
// candidate
const auto isDistinct = [&](const std::size_t index, const double deviation) {
/*
If the neighbor is not possible to enter, we allow for a lower
distinction rate. If the road category is smaller, its also adjusted. Only
roads of the same priority require the full distinction ratio.
*/
const auto &best_option_data =
node_based_graph.GetEdgeData(intersection[best_option].eid);
const auto adjusted_distinction_ratio = [&]() {
// not allowed competitors are easily distinct
if (!intersection[index].entry_allowed)
return 0.7 * DISTINCTION_RATIO;
// a bit less obvious are road classes
else if (in_way_data.road_classification == best_option_data.road_classification &&
best_option_data.road_classification.GetPriority() <
node_based_graph.GetEdgeData(intersection[index].eid)
.road_classification.GetPriority())
return 0.8 * DISTINCTION_RATIO;
// if road classes are the same, we use the full ratio
else
return DISTINCTION_RATIO;
}();
return index == 0 || deviation / best_option_deviation >= adjusted_distinction_ratio ||
(deviation <= NARROW_TURN_ANGLE && !intersection[index].entry_allowed);
};
const bool distinct_to_left = isDistinct(left_index, left_deviation);
const bool distinct_to_right = isDistinct(right_index, right_deviation);
// Well distinct turn that is nearly straight
if ((distinct_to_left || obvious_to_left) && (distinct_to_right || obvious_to_right))
return best_option;
}
else
{
const auto &continue_data = node_based_graph.GetEdgeData(intersection[best_continue].eid);
if (std::abs(best_continue_deviation) < 1)
return best_continue;
// check if any other similar best continues exist
std::size_t i, last = intersection.size();
for (i = 1; i < last; ++i)
{
if (i == best_continue || !intersection[i].entry_allowed)
continue;
const auto &turn_data = node_based_graph.GetEdgeData(intersection[i].eid);
const bool is_obvious_by_road_class =
obviousByRoadClass(in_way_data.road_classification,
continue_data.road_classification,
turn_data.road_classification);
// if the main road is obvious by class, we ignore the current road as a potential
// prevention of obviousness
if (is_obvious_by_road_class)
continue;
// continuation could be grouped with a straight turn and the turning road is a ramp
if (turn_data.road_classification.IsRampClass() &&
best_continue_deviation < GROUP_ANGLE &&
!continue_data.road_classification.IsRampClass())
continue;
// perfectly straight turns prevent obviousness
const auto turn_deviation = angularDeviation(intersection[i].angle, STRAIGHT_ANGLE);
if (turn_deviation < FUZZY_ANGLE_DIFFERENCE)
return 0;
const auto deviation_ratio = turn_deviation / best_continue_deviation;
// in comparison to normal deviations, a continue road can offer a smaller distinction
// ratio. Other roads close to the turn angle are not as obvious, if one road continues.
if (deviation_ratio < DISTINCTION_RATIO / 1.5)
return 0;
/* in comparison to another continuing road, we need a better distinction. This prevents
situations where the turn is probably less obvious. An example are places that have a
road with the same name entering/exiting:
d
/
/
a -- b
\
\
c
*/
const auto same_name = !util::guidance::requiresNameAnnounced(
turn_data.name_id, continue_data.name_id, name_table, street_name_suffix_table);
if (same_name && deviation_ratio < 1.5 * DISTINCTION_RATIO)
return 0;
}
// Segregated intersections can result in us finding an obvious turn, even though its only
// obvious due to a very short segment in between. So if the segment coming in is very
// short, we check the previous intersection for other continues in the opposite bearing.
const auto node_at_intersection = node_based_graph.GetTarget(via_edge);
const double constexpr MAX_COLLAPSE_DISTANCE = 30;
const auto distance_at_u_turn = intersection[0].segment_length;
if (distance_at_u_turn < MAX_COLLAPSE_DISTANCE)
{
// this request here actually goes against the direction of the ingoing edgeid. This can
// even reverse the direction. Since we don't want to compute actual turns but simply
// try to find whether there is a turn going to the opposite direction of our obvious
// turn, this should be alright.
NodeID new_node;
const auto previous_intersection = [&]() {
EdgeID turn_edge;
std::tie(new_node, turn_edge) = intersection_generator.SkipDegreeTwoNodes(
node_at_intersection, intersection[0].eid);
return intersection_generator.GetConnectedRoads(new_node, turn_edge);
}();
if (new_node != node_at_intersection)
{
const auto continue_road = intersection[best_continue];
for (const auto &comparison_road : previous_intersection)
{
// since we look at the intersection in the wrong direction, a similar angle
// actually represents a near 180 degree different in bearings between the two
// roads. So if there is a road that is enterable in the opposite direction just
// prior, a turn is not obvious
const auto &turn_data = node_based_graph.GetEdgeData(comparison_road.eid);
if (angularDeviation(comparison_road.angle, STRAIGHT_ANGLE) > GROUP_ANGLE &&
angularDeviation(comparison_road.angle, continue_road.angle) <
FUZZY_ANGLE_DIFFERENCE &&
!turn_data.reversed && continue_data.CanCombineWith(turn_data))
return 0;
}
}
}
return best_continue;
}
return 0;
}
} // namespace guidance
} // namespace extractor
} // namespace osrm
@@ -1,118 +0,0 @@
#ifndef OSRM_EXTRACTOR_GUIDANCE_INTERSECTION_NORMALIZER_HPP_
#define OSRM_EXTRACTOR_GUIDANCE_INTERSECTION_NORMALIZER_HPP_
#include "util/typedefs.hpp"
#include "util/attributes.hpp"
#include "extractor/guidance/coordinate_extractor.hpp"
#include "extractor/guidance/intersection.hpp"
#include "extractor/guidance/intersection_generator.hpp"
#include "extractor/query_node.hpp"
#include "extractor/suffix_table.hpp"
#include "util/name_table.hpp"
#include <utility>
#include <vector>
namespace osrm
{
namespace extractor
{
namespace guidance
{
/*
* An intersection is a central part in computing guidance decisions. However the model in OSM and
* the view we want to use in guidance are not necessarily the same thing. We have to account for
* some models that are chosen explicitly in OSM and that don't actually describe how a human would
* experience an intersection.
*
* For example, if a small pedestrian island is located at a traffic light right in the middle of a
* road, OSM tends to model the road as two separate ways. A human would consider these two ways a
* single road, though. In this normalizer, we try to account for these subtle differences between
* OSM data and human perception to improve our decision base for guidance later on.
*/
class IntersectionNormalizer
{
public:
IntersectionNormalizer(const util::NodeBasedDynamicGraph &node_based_graph,
const std::vector<extractor::QueryNode> &node_coordinates,
const util::NameTable &name_table,
const SuffixTable &street_name_suffix_table,
const IntersectionGenerator &intersection_generator);
// The function takes an intersection an converts it to a `perceived` intersection which closer
// represents how a human might experience the intersection
OSRM_ATTR_WARN_UNUSED
std::pair<IntersectionShape, std::vector<std::pair<EdgeID, EdgeID>>>
operator()(const NodeID node_at_intersection, IntersectionShape intersection) const;
private:
const util::NodeBasedDynamicGraph &node_based_graph;
const std::vector<extractor::QueryNode> &node_coordinates;
const util::NameTable &name_table;
const SuffixTable &street_name_suffix_table;
const IntersectionGenerator &intersection_generator;
/* check if two indices in an intersection can be seen as a single road in the perceived
* intersection representation. See below for an example. Utility function for
* MergeSegregatedRoads. It also checks for neighboring merges.
* This is due possible segments where multiple roads could end up being merged into one.
* We only support merging two roads, not three or more, though.
* c c
* / /
* a - b -> a - b - (c,d) but not a - b d -> a,b,(cde)
* \ \
* d e
*/
bool CanMerge(const NodeID intersection_node,
const IntersectionShape &intersection,
std::size_t first_index,
std::size_t second_index) const;
// A tool called by CanMerge. It checks whether two indices can be merged, not concerned without
// remaining parts of the intersection.
bool InnerCanMerge(const NodeID intersection_node,
const IntersectionShape &intersection,
std::size_t first_index,
std::size_t second_index) const;
// Merge segregated roads to omit invalid turns in favor of treating segregated roads as
// one.
// This function combines roads the following way:
//
// * *
// * is converted to *
// v ^ +
// v ^ +
//
// The treatment results in a straight turn angle of 180º rather than a turn angle of approx
// 160
OSRM_ATTR_WARN_UNUSED
std::pair<IntersectionShape, std::vector<std::pair<EdgeID, EdgeID>>>
MergeSegregatedRoads(const NodeID intersection_node, IntersectionShape intersection) const;
// The counterpiece to mergeSegregatedRoads. While we can adjust roads that split up at the
// intersection itself, it can also happen that intersections are connected to joining roads.
//
// * *
// * is converted to *
// v a --- a ---
// v ^ +
// v ^ +
// b
//
// for the local view of b at a.
OSRM_ATTR_WARN_UNUSED
IntersectionShape AdjustBearingsForMergeAtDestination(const NodeID node_at_intersection,
IntersectionShape intersection) const;
};
} // namespace guidance
} // namespace extractor
} // namespace osrm
#endif /* OSRM_EXTRACTOR_GUIDANCE_INTERSECTION_NORMALIZER_HPP_ */
@@ -0,0 +1,22 @@
#ifndef OSRM_EXTRACTOR_GUIDANCE_INTERSECTION_SCENARIO_THREE_WAY_HPP_
#define OSRM_EXTRACTOR_GUIDANCE_INTERSECTION_SCENARIO_THREE_WAY_HPP_
#include "extractor/guidance/intersection.hpp"
namespace osrm
{
namespace extractor
{
namespace guidance
{
// Ending in a T-Intersection
bool isEndOfRoad(const ConnectedRoad &uturn,
const ConnectedRoad &possible_right_turn,
const ConnectedRoad &possible_left_turn);
} // namespace guidance
} // namespace extractor
} // namespace osrm
#endif /*OSRM_EXTRACTOR_GUIDANCE_INTERSECTION_SCENARIO_THREE_WAY_HPP_*/
@@ -3,8 +3,9 @@
#include "extractor/guidance/constants.hpp"
#include "extractor/guidance/intersection_generator.hpp"
#include "extractor/guidance/toolkit.hpp"
#include "extractor/guidance/toolkit.hpp"
#include "util/coordinate.hpp"
#include "util/coordinate_calculation.hpp"
#include "util/node_based_graph.hpp"
#include "util/typedefs.hpp"
@@ -20,6 +21,9 @@ namespace extractor
namespace guidance
{
// forward declaration to allow interaction between the intersection generator and the graph hopper
class IntersectionGenerator;
/*
* The graph hopper is a utility that lets you find certain intersections with a node based graph,
* accumulating information along the way
@@ -42,7 +46,7 @@ class NodeBasedGraphWalker
boost::optional<std::pair<NodeID, EdgeID>> TraverseRoad(NodeID starting_at_node_id,
EdgeID following_edge_id,
accumulator_type &accumulator,
const selector_type &selector) const;
const selector_type &selector);
private:
const util::NodeBasedDynamicGraph &node_based_graph;
@@ -86,8 +90,7 @@ struct LengthLimitedCoordinateAccumulator
};
/*
* The SelectRoadByNameOnlyChoiceAndStraightness tries to follow a given name along a route. We
* offer methods to skip
* The SelectRoadByNameOnlyChoiceAndStraightness tries to follow a given name along a route. We offer methods to skip
* over bridges/similar situations if desired, following narrow turns
* This struct offers an example implementation of a possible road selector for traversing the
* node-based graph using the NodeBasedGraphWalker
@@ -115,13 +118,14 @@ struct SelectRoadByNameOnlyChoiceAndStraightness
// find the next intersection given a hop limit
struct IntersectionFinderAccumulator
{
IntersectionFinderAccumulator(const std::uint8_t hop_limit,
const IntersectionGenerator &intersection_generator);
IntersectionFinderAccumulator(const std::uint8_t hop_limit, const IntersectionGenerator &intersection_generator);
// true if the path has traversed enough distance
bool terminate();
// update the accumulator
void update(const NodeID from_node, const EdgeID via_edge, const NodeID to_node);
void update(const NodeID from_node,
const EdgeID via_edge,
const NodeID to_node);
std::uint8_t hops;
const std::uint8_t hop_limit;
@@ -132,15 +136,17 @@ struct IntersectionFinderAccumulator
// the result we are looking for
NodeID nid;
EdgeID via_edge_id;
IntersectionView intersection;
Intersection intersection;
};
template <class accumulator_type, class selector_type>
boost::optional<std::pair<NodeID, EdgeID>>
NodeBasedGraphWalker::TraverseRoad(NodeID current_node_id,
EdgeID current_edge_id,
accumulator_type &accumulator,
const selector_type &selector) const
const selector_type &selector)
{
/*
* since graph hopping is used in many ways, we don't generate an adjusted intersection
@@ -191,60 +197,6 @@ NodeBasedGraphWalker::TraverseRoad(NodeID current_node_id,
return {};
}
struct SkipTrafficSignalBarrierRoadSelector
{
boost::optional<EdgeID> operator()(const NodeID,
const EdgeID,
const IntersectionView &intersection,
const util::NodeBasedDynamicGraph &) const
{
if (intersection.isTrafficSignalOrBarrier())
{
return boost::make_optional(intersection[1].eid);
}
else
{
return boost::none;
}
}
};
struct DistanceToNextIntersectionAccumulator
{
DistanceToNextIntersectionAccumulator(
const extractor::guidance::CoordinateExtractor &extractor_,
const util::NodeBasedDynamicGraph &graph_,
const double threshold)
: extractor{extractor_}, graph{graph_}, threshold{threshold}
{
}
bool terminate()
{
if (distance > threshold)
{
too_far_away = true;
return true;
}
return false;
}
void update(const NodeID start, const EdgeID onto, const NodeID)
{
using namespace util::coordinate_calculation;
const auto coords = extractor.GetForwardCoordinatesAlongRoad(start, onto);
distance += getLength(coords, &haversineDistance);
}
const extractor::guidance::CoordinateExtractor &extractor;
const util::NodeBasedDynamicGraph &graph;
const double threshold;
bool too_far_away = false;
double distance = 0.;
};
} // namespace guidance
} // namespace extractor
} // namespace osrm
@@ -1,112 +0,0 @@
#ifndef OSRM_GUIDANCE_PARSING_TOOLKIT_HPP_
#define OSRM_GUIDANCE_PARSING_TOOLKIT_HPP_
#include <cstdint>
#include <string>
#include <boost/algorithm/string.hpp>
#include <boost/tokenizer.hpp>
#include "util/attributes.hpp"
namespace osrm
{
namespace extractor
{
namespace guidance
{
// Public service vehicle lanes and similar can introduce additional lanes into the lane string that
// are not specifically marked for left/right turns. This function can be used from the profile to
// trim the lane string appropriately
//
// left|throught|
// in combination with lanes:psv:forward=1
// will be corrected to left|throught, since the final lane is not drivable.
// This is in contrast to a situation with lanes:psv:forward=0 (or not set) where left|through|
// represents left|through|through
OSRM_ATTR_WARN_UNUSED
inline std::string
trimLaneString(std::string lane_string, std::int32_t count_left, std::int32_t count_right)
{
if (count_left)
{
bool sane = count_left < static_cast<std::int32_t>(lane_string.size());
for (std::int32_t i = 0; i < count_left; ++i)
// this is adjusted for our fake pipe. The moment cucumber can handle multiple escaped
// pipes, the '&' part can be removed
if (lane_string[i] != '|')
{
sane = false;
break;
}
if (sane)
{
lane_string.erase(lane_string.begin(), lane_string.begin() + count_left);
}
}
if (count_right)
{
bool sane = count_right < static_cast<std::int32_t>(lane_string.size());
for (auto itr = lane_string.rbegin();
itr != lane_string.rend() && itr != lane_string.rbegin() + count_right;
++itr)
{
if (*itr != '|')
{
sane = false;
break;
}
}
if (sane)
lane_string.resize(lane_string.size() - count_right);
}
return lane_string;
}
// https://github.com/Project-OSRM/osrm-backend/issues/2638
// It can happen that some lanes are not drivable by car. Here we handle this tagging scheme
// (vehicle:lanes) to filter out not-allowed roads
// lanes=3
// turn:lanes=left|through|through|right
// vehicle:lanes=yes|yes|no|yes
// bicycle:lanes=yes|no|designated|yes
OSRM_ATTR_WARN_UNUSED
inline std::string applyAccessTokens(std::string lane_string, const std::string &access_tokens)
{
typedef boost::tokenizer<boost::char_separator<char>> tokenizer;
boost::char_separator<char> sep("|", "", boost::keep_empty_tokens);
tokenizer tokens(lane_string, sep);
tokenizer access(access_tokens, sep);
// strings don't match, don't do anything
if (std::distance(std::begin(tokens), std::end(tokens)) !=
std::distance(std::begin(access), std::end(access)))
return lane_string;
std::string result_string = "";
const static std::string yes = "yes";
for (auto token_itr = std::begin(tokens), access_itr = std::begin(access);
token_itr != std::end(tokens);
++token_itr, ++access_itr)
{
if (*access_itr == yes)
{
// we have to add this in front, because the next token could be invalid. Doing this on
// non-empty strings makes sure that the token string will be valid in the end
if (!result_string.empty())
result_string += '|';
result_string += *token_itr;
}
}
return result_string;
}
} // namespace guidance
} // namespace extractor
} // namespace osrm
#endif // OSRM_GUIDANCE_PARSING_TOOLKIT_HPP_
@@ -4,8 +4,9 @@
#include <cmath>
#include <cstdint>
#include <string>
#include <unordered_map>
#include "extractor/guidance/constants.hpp"
#include <osmium/osm.hpp>
namespace osrm
{
@@ -64,7 +65,7 @@ class RoadClassification
public:
// default construction
RoadClassification()
: motorway_class(0), link_class(0), may_be_ignored(0),
: motorway_class(0), link_class(0), may_be_ignored(1),
road_priority_class(RoadPriorityClass::CONNECTIVITY), number_of_lanes(0)
{
}
@@ -125,22 +126,6 @@ inline bool canBeSeenAsFork(const RoadClassification first, const RoadClassifica
return std::abs(static_cast<int>(first.GetPriority()) -
static_cast<int>(second.GetPriority())) <= 1;
}
inline bool obviousByRoadClass(const RoadClassification in_classification,
const RoadClassification obvious_candidate,
const RoadClassification compare_candidate)
{
// lower numbers are of higher priority
const bool has_high_priority = PRIORITY_DISTINCTION_FACTOR * obvious_candidate.GetPriority() <
compare_candidate.GetPriority();
const bool continues_on_same_class = in_classification == obvious_candidate;
return (has_high_priority && continues_on_same_class) ||
(!obvious_candidate.IsLowPriorityRoadClass() &&
!in_classification.IsLowPriorityRoadClass() &&
compare_candidate.IsLowPriorityRoadClass());
}
} // namespace guidance
} // namespace extractor
} // namespace osrm
@@ -15,6 +15,7 @@
#include "util/typedefs.hpp"
#include <unordered_set>
#include <utility>
#include <vector>
namespace osrm
@@ -9,10 +9,10 @@
#include "util/name_table.hpp"
#include "util/node_based_graph.hpp"
#include <cstddef>
#include <utility>
#include <vector>
#include <boost/optional.hpp>
namespace osrm
{
namespace extractor
@@ -22,7 +22,7 @@ namespace guidance
// Intersection handlers deal with all issues related to intersections.
// They assign appropriate turn operations to the TurnOperations.
class SliproadHandler final : public IntersectionHandler
class SliproadHandler : public IntersectionHandler
{
public:
SliproadHandler(const IntersectionGenerator &intersection_generator,
@@ -42,37 +42,6 @@ class SliproadHandler final : public IntersectionHandler
Intersection operator()(const NodeID nid,
const EdgeID via_eid,
Intersection intersection) const override final;
private:
boost::optional<std::size_t> getObviousIndexWithSliproads(const EdgeID from,
const Intersection &intersection,
const NodeID at) const;
// Next intersection from `start` onto `onto` is too far away for a Siproad scenario
bool nextIntersectionIsTooFarAway(const NodeID start, const EdgeID onto) const;
// Through street: does a road continue with from's name at the intersection
bool isThroughStreet(const EdgeID from, const IntersectionView &intersection) const;
// Does the road from `current` to `next` continue
bool roadContinues(const EdgeID current, const EdgeID next) const;
// Is the area under the triangle a valid Sliproad triangle
bool isValidSliproadArea(const double max_area, const NodeID, const NodeID, const NodeID) const;
// Is the Sliproad a link the both roads it shortcuts must not be links
bool isValidSliproadLink(const IntersectionViewData &sliproad,
const IntersectionViewData &first,
const IntersectionViewData &second) const;
// Could a Sliproad reach this intersection?
static bool canBeTargetOfSliproad(const IntersectionView &intersection);
// Scales a threshold based on the underlying road classification.
// Example: a 100 m threshold for a highway if different on living streets.
// The return value is guaranteed to not be larger than `threshold`.
static double scaledThresholdByRoadClass(const double max_threshold,
const RoadClassification &classification);
};
} // namespace guidance
+240
View File
@@ -0,0 +1,240 @@
#ifndef OSRM_GUIDANCE_TOOLKIT_HPP_
#define OSRM_GUIDANCE_TOOLKIT_HPP_
#include "util/attributes.hpp"
#include "util/bearing.hpp"
#include "util/coordinate.hpp"
#include "util/coordinate_calculation.hpp"
#include "util/guidance/toolkit.hpp"
#include "util/guidance/turn_lanes.hpp"
#include "util/node_based_graph.hpp"
#include "util/typedefs.hpp"
#include "extractor/compressed_edge_container.hpp"
#include "extractor/query_node.hpp"
#include "extractor/guidance/constants.hpp"
#include "extractor/guidance/intersection.hpp"
#include "extractor/guidance/road_classification.hpp"
#include "extractor/guidance/turn_instruction.hpp"
#include <algorithm>
#include <cmath>
#include <cstdint>
#include <string>
#include <unordered_map>
#include <utility>
#include <vector>
#include <boost/algorithm/string.hpp>
#include <boost/functional/hash.hpp>
#include <boost/range/iterator_range.hpp>
#include <boost/tokenizer.hpp>
namespace osrm
{
namespace extractor
{
namespace guidance
{
using util::guidance::LaneTupleIdPair;
using LaneDataIdMap = std::unordered_map<LaneTupleIdPair, LaneDataID, boost::hash<LaneTupleIdPair>>;
using util::guidance::angularDeviation;
using util::guidance::entersRoundabout;
using util::guidance::leavesRoundabout;
// To simplify handling of Left/Right hand turns, we can mirror turns and write an intersection
// handler only for one side. The mirror function turns a left-hand turn in a equivalent right-hand
// turn and vice versa.
inline bool hasRoundaboutType(const TurnInstruction instruction)
{
using namespace extractor::guidance::TurnType;
const constexpr TurnType::Enum valid_types[] = {TurnType::EnterRoundabout,
TurnType::EnterAndExitRoundabout,
TurnType::EnterRotary,
TurnType::EnterAndExitRotary,
TurnType::EnterRoundaboutIntersection,
TurnType::EnterAndExitRoundaboutIntersection,
TurnType::EnterRoundaboutAtExit,
TurnType::ExitRoundabout,
TurnType::EnterRotaryAtExit,
TurnType::ExitRotary,
TurnType::EnterRoundaboutIntersectionAtExit,
TurnType::ExitRoundaboutIntersection,
TurnType::StayOnRoundabout};
const auto *first = valid_types;
const auto *last = first + sizeof(valid_types) / sizeof(valid_types[0]);
return std::find(first, last, instruction.type) != last;
}
// Public service vehicle lanes and similar can introduce additional lanes into the lane string that
// are not specifically marked for left/right turns. This function can be used from the profile to
// trim the lane string appropriately
//
// left|throught|
// in combination with lanes:psv:forward=1
// will be corrected to left|throught, since the final lane is not drivable.
// This is in contrast to a situation with lanes:psv:forward=0 (or not set) where left|through|
// represents left|through|through
OSRM_ATTR_WARN_UNUSED
inline std::string
trimLaneString(std::string lane_string, std::int32_t count_left, std::int32_t count_right)
{
if (count_left)
{
bool sane = count_left < static_cast<std::int32_t>(lane_string.size());
for (std::int32_t i = 0; i < count_left; ++i)
// this is adjusted for our fake pipe. The moment cucumber can handle multiple escaped
// pipes, the '&' part can be removed
if (lane_string[i] != '|')
{
sane = false;
break;
}
if (sane)
{
lane_string.erase(lane_string.begin(), lane_string.begin() + count_left);
}
}
if (count_right)
{
bool sane = count_right < static_cast<std::int32_t>(lane_string.size());
for (auto itr = lane_string.rbegin();
itr != lane_string.rend() && itr != lane_string.rbegin() + count_right;
++itr)
{
if (*itr != '|')
{
sane = false;
break;
}
}
if (sane)
lane_string.resize(lane_string.size() - count_right);
}
return lane_string;
}
// https://github.com/Project-OSRM/osrm-backend/issues/2638
// It can happen that some lanes are not drivable by car. Here we handle this tagging scheme
// (vehicle:lanes) to filter out not-allowed roads
// lanes=3
// turn:lanes=left|through|through|right
// vehicle:lanes=yes|yes|no|yes
// bicycle:lanes=yes|no|designated|yes
OSRM_ATTR_WARN_UNUSED
inline std::string applyAccessTokens(std::string lane_string, const std::string &access_tokens)
{
typedef boost::tokenizer<boost::char_separator<char>> tokenizer;
boost::char_separator<char> sep("|", "", boost::keep_empty_tokens);
tokenizer tokens(lane_string, sep);
tokenizer access(access_tokens, sep);
// strings don't match, don't do anything
if (std::distance(std::begin(tokens), std::end(tokens)) !=
std::distance(std::begin(access), std::end(access)))
return lane_string;
std::string result_string = "";
const static std::string yes = "yes";
for (auto token_itr = std::begin(tokens), access_itr = std::begin(access);
token_itr != std::end(tokens);
++token_itr, ++access_itr)
{
if (*access_itr == yes)
{
// we have to add this in front, because the next token could be invalid. Doing this on
// non-empty strings makes sure that the token string will be valid in the end
if (!result_string.empty())
result_string += '|';
result_string += *token_itr;
}
}
return result_string;
}
inline bool obviousByRoadClass(const RoadClassification in_classification,
const RoadClassification obvious_candidate,
const RoadClassification compare_candidate)
{
const bool has_high_priority = PRIORITY_DISTINCTION_FACTOR * obvious_candidate.GetPriority() <
compare_candidate.GetPriority();
const bool continues_on_same_class = in_classification == obvious_candidate;
return (has_high_priority && continues_on_same_class) ||
(!obvious_candidate.IsLowPriorityRoadClass() &&
!in_classification.IsLowPriorityRoadClass() &&
compare_candidate.IsLowPriorityRoadClass());
}
/* We use the sum of least squares to calculate a linear regression through our
* coordinates.
* This regression gives a good idea of how the road can be perceived and corrects for
* initial and final corrections
*/
inline std::pair<util::Coordinate, util::Coordinate>
leastSquareRegression(const std::vector<util::Coordinate> &coordinates)
{
BOOST_ASSERT(coordinates.size() >= 2);
double sum_lon = 0, sum_lat = 0, sum_lon_lat = 0, sum_lon_lon = 0;
double min_lon = static_cast<double>(toFloating(coordinates.front().lon));
double max_lon = static_cast<double>(toFloating(coordinates.front().lon));
for (const auto coord : coordinates)
{
min_lon = std::min(min_lon, static_cast<double>(toFloating(coord.lon)));
max_lon = std::max(max_lon, static_cast<double>(toFloating(coord.lon)));
sum_lon += static_cast<double>(toFloating(coord.lon));
sum_lon_lon +=
static_cast<double>(toFloating(coord.lon)) * static_cast<double>(toFloating(coord.lon));
sum_lat += static_cast<double>(toFloating(coord.lat));
sum_lon_lat +=
static_cast<double>(toFloating(coord.lon)) * static_cast<double>(toFloating(coord.lat));
}
const auto dividend = coordinates.size() * sum_lon_lat - sum_lon * sum_lat;
const auto divisor = coordinates.size() * sum_lon_lon - sum_lon * sum_lon;
if (std::abs(divisor) < std::numeric_limits<double>::epsilon())
return std::make_pair(coordinates.front(), coordinates.back());
// slope of the regression line
const auto slope = dividend / divisor;
const auto intercept = (sum_lat - slope * sum_lon) / coordinates.size();
const auto GetLatAtLon = [intercept,
slope](const util::FloatLongitude longitude) -> util::FloatLatitude {
return {intercept + slope * static_cast<double>((longitude))};
};
const util::Coordinate regression_first = {
toFixed(util::FloatLongitude{min_lon - 1}),
toFixed(util::FloatLatitude(GetLatAtLon(util::FloatLongitude{min_lon - 1})))};
const util::Coordinate regression_end = {
toFixed(util::FloatLongitude{max_lon + 1}),
toFixed(util::FloatLatitude(GetLatAtLon(util::FloatLongitude{max_lon + 1})))};
return {regression_first, regression_end};
}
inline std::uint8_t getLaneCountAtIntersection(const NodeID intersection_node,
const util::NodeBasedDynamicGraph &node_based_graph)
{
std::uint8_t lanes = 0;
for (const EdgeID onto_edge : node_based_graph.GetAdjacentEdgeRange(intersection_node))
lanes = std::max(
lanes, node_based_graph.GetEdgeData(onto_edge).road_classification.GetNumberOfLanes());
return lanes;
}
} // namespace guidance
} // namespace extractor
} // namespace osrm
#endif // OSRM_GUIDANCE_TOOLKIT_HPP_
+9 -33
View File
@@ -4,17 +4,16 @@
#include "extractor/compressed_edge_container.hpp"
#include "extractor/guidance/intersection.hpp"
#include "extractor/guidance/intersection_generator.hpp"
#include "extractor/guidance/intersection_normalizer.hpp"
#include "extractor/guidance/motorway_handler.hpp"
#include "extractor/guidance/roundabout_handler.hpp"
#include "extractor/guidance/sliproad_handler.hpp"
#include "extractor/guidance/toolkit.hpp"
#include "extractor/guidance/turn_classification.hpp"
#include "extractor/guidance/turn_handler.hpp"
#include "extractor/query_node.hpp"
#include "extractor/restriction_map.hpp"
#include "extractor/suffix_table.hpp"
#include "util/attributes.hpp"
#include "util/name_table.hpp"
#include "util/node_based_graph.hpp"
@@ -22,7 +21,6 @@
#include <memory>
#include <string>
#include <tuple>
#include <unordered_set>
#include <utility>
#include <vector>
@@ -36,6 +34,7 @@ namespace guidance
class TurnAnalysis
{
public:
TurnAnalysis(const util::NodeBasedDynamicGraph &node_based_graph,
const std::vector<QueryNode> &node_info_list,
@@ -46,42 +45,19 @@ class TurnAnalysis
const SuffixTable &street_name_suffix_table,
const ProfileProperties &profile_properties);
/* Full Analysis Process for a single node/edge combination. Use with caution, as the process is
* relatively expensive */
OSRM_ATTR_WARN_UNUSED
Intersection operator()(const NodeID node_prior_to_intersection,
const EdgeID entering_via_edge) const;
// the entry into the turn analysis
Intersection getIntersection(const NodeID from_node, const EdgeID via_eid) const;
Intersection
assignTurnTypes(const NodeID from_node, const EdgeID via_eid, Intersection intersection) const;
/*
* Returns a normalized intersection without any assigned turn types.
* This intersection can be used as input for intersection classification, turn lane assignment
* and similar.
*/
struct ShapeResult
{
// the basic shape, containing all turns
IntersectionShape intersection_shape;
// normalised shape, merged some roads into others, adjusted bearings
// see intersection_normaliser for further explanations
IntersectionShape normalised_intersection_shape;
// map containing information about which road was merged into which
std::vector<std::pair<EdgeID, EdgeID>> merging_map;
};
OSRM_ATTR_WARN_UNUSED
ShapeResult ComputeIntersectionShapes(const NodeID node_at_center_of_intersection) const;
std::vector<TurnOperation>
transformIntersectionIntoTurns(const Intersection &intersection) const;
// Select turn types based on the intersection shape
OSRM_ATTR_WARN_UNUSED
Intersection AssignTurnTypes(const NodeID from_node,
const EdgeID via_eid,
const IntersectionView &intersection) const;
const IntersectionGenerator &GetIntersectionGenerator() const;
const IntersectionGenerator &getGenerator() const;
private:
const util::NodeBasedDynamicGraph &node_based_graph;
const IntersectionGenerator intersection_generator;
const IntersectionNormalizer intersection_normalizer;
const RoundaboutHandler roundabout_handler;
const MotorwayHandler motorway_handler;
const TurnHandler turn_handler;
@@ -1,12 +1,21 @@
#ifndef OSRM_GUIDANCE_TURN_CLASSIFICATION_HPP_
#define OSRM_GUIDANCE_TURN_CLASSIFICATION_HPP_
#include "extractor/compressed_edge_container.hpp"
#include "extractor/guidance/intersection.hpp"
#include "extractor/guidance/toolkit.hpp"
#include "extractor/query_node.hpp"
#include "util/coordinate.hpp"
#include "util/guidance/bearing_class.hpp"
#include "util/guidance/entry_class.hpp"
#include "util/node_based_graph.hpp"
#include "util/typedefs.hpp"
#include <algorithm>
#include <cstddef>
#include <utility>
#include <vector>
namespace osrm
{
@@ -2,9 +2,11 @@
#define OSRM_EXTRACTOR_GUIDANCE_TURN_DISCOVERY_HPP_
#include "extractor/guidance/intersection.hpp"
#include "extractor/guidance/intersection_generator.hpp"
#include "extractor/guidance/turn_analysis.hpp"
#include "util/typedefs.hpp"
#include <string>
namespace osrm
{
namespace extractor
@@ -20,13 +22,13 @@ namespace lanes
bool findPreviousIntersection(
const NodeID node,
const EdgeID via_edge,
const Intersection &intersection,
const IntersectionGenerator &intersection_generator,
const Intersection intersection,
const TurnAnalysis &turn_analysis, // to generate other intersections
const util::NodeBasedDynamicGraph &node_based_graph, // query edge data
// output parameters, will be in an arbitrary state on failure
NodeID &result_node,
EdgeID &result_via_edge,
IntersectionView &result_intersection);
Intersection &result_intersection);
} // namespace lanes
} // namespace guidance
+2 -158
View File
@@ -1,11 +1,11 @@
#ifndef OSRM_GUIDANCE_TURN_INSTRUCTION_HPP_
#define OSRM_GUIDANCE_TURN_INSTRUCTION_HPP_
#include <algorithm>
#include <cstdint>
#include <boost/assert.hpp>
#include "extractor/guidance/roundabout_type.hpp"
#include "util/attributes.hpp"
#include "util/typedefs.hpp"
namespace osrm
@@ -150,162 +150,6 @@ inline bool operator==(const TurnInstruction lhs, const TurnInstruction rhs)
return lhs.type == rhs.type && lhs.direction_modifier == rhs.direction_modifier;
}
// check if a instruction is associated in any form with a roundabout
inline bool hasRoundaboutType(const TurnInstruction instruction)
{
using namespace extractor::guidance::TurnType;
const constexpr TurnType::Enum valid_types[] = {TurnType::EnterRoundabout,
TurnType::EnterAndExitRoundabout,
TurnType::EnterRotary,
TurnType::EnterAndExitRotary,
TurnType::EnterRoundaboutIntersection,
TurnType::EnterAndExitRoundaboutIntersection,
TurnType::EnterRoundaboutAtExit,
TurnType::ExitRoundabout,
TurnType::EnterRotaryAtExit,
TurnType::ExitRotary,
TurnType::EnterRoundaboutIntersectionAtExit,
TurnType::ExitRoundaboutIntersection,
TurnType::StayOnRoundabout};
const auto *first = valid_types;
const auto *last = first + sizeof(valid_types) / sizeof(valid_types[0]);
return std::find(first, last, instruction.type) != last;
}
inline bool entersRoundabout(const extractor::guidance::TurnInstruction instruction)
{
return (instruction.type == extractor::guidance::TurnType::EnterRoundabout ||
instruction.type == extractor::guidance::TurnType::EnterRotary ||
instruction.type == extractor::guidance::TurnType::EnterRoundaboutIntersection ||
instruction.type == extractor::guidance::TurnType::EnterRoundaboutAtExit ||
instruction.type == extractor::guidance::TurnType::EnterRotaryAtExit ||
instruction.type == extractor::guidance::TurnType::EnterRoundaboutIntersectionAtExit ||
instruction.type == extractor::guidance::TurnType::EnterAndExitRoundabout ||
instruction.type == extractor::guidance::TurnType::EnterAndExitRotary ||
instruction.type == extractor::guidance::TurnType::EnterAndExitRoundaboutIntersection);
}
inline bool leavesRoundabout(const extractor::guidance::TurnInstruction instruction)
{
return (instruction.type == extractor::guidance::TurnType::ExitRoundabout ||
instruction.type == extractor::guidance::TurnType::ExitRotary ||
instruction.type == extractor::guidance::TurnType::ExitRoundaboutIntersection ||
instruction.type == extractor::guidance::TurnType::EnterAndExitRoundabout ||
instruction.type == extractor::guidance::TurnType::EnterAndExitRotary ||
instruction.type == extractor::guidance::TurnType::EnterAndExitRoundaboutIntersection);
}
inline bool staysOnRoundabout(const extractor::guidance::TurnInstruction instruction)
{
return instruction.type == extractor::guidance::TurnType::StayOnRoundabout;
}
// Silent Turn Instructions are not to be mentioned to the outside world but
inline bool isSilent(const extractor::guidance::TurnInstruction instruction)
{
return instruction.type == extractor::guidance::TurnType::NoTurn ||
instruction.type == extractor::guidance::TurnType::Suppressed ||
instruction.type == extractor::guidance::TurnType::StayOnRoundabout;
}
inline bool hasRampType(const extractor::guidance::TurnInstruction instruction)
{
return instruction.type == extractor::guidance::TurnType::OffRamp ||
instruction.type == extractor::guidance::TurnType::OnRamp;
}
inline extractor::guidance::DirectionModifier::Enum getTurnDirection(const double angle)
{
// An angle of zero is a u-turn
// 180 goes perfectly straight
// 0-180 are right turns
// 180-360 are left turns
if (angle > 0 && angle < 60)
return extractor::guidance::DirectionModifier::SharpRight;
if (angle >= 60 && angle < 140)
return extractor::guidance::DirectionModifier::Right;
if (angle >= 140 && angle < 160)
return extractor::guidance::DirectionModifier::SlightRight;
if (angle >= 160 && angle <= 200)
return extractor::guidance::DirectionModifier::Straight;
if (angle > 200 && angle <= 220)
return extractor::guidance::DirectionModifier::SlightLeft;
if (angle > 220 && angle <= 300)
return extractor::guidance::DirectionModifier::Left;
if (angle > 300 && angle < 360)
return extractor::guidance::DirectionModifier::SharpLeft;
return extractor::guidance::DirectionModifier::UTurn;
}
// swaps left <-> right modifier types
OSRM_ATTR_WARN_UNUSED
inline extractor::guidance::DirectionModifier::Enum
mirrorDirectionModifier(const extractor::guidance::DirectionModifier::Enum modifier)
{
const constexpr extractor::guidance::DirectionModifier::Enum results[] = {
extractor::guidance::DirectionModifier::UTurn,
extractor::guidance::DirectionModifier::SharpLeft,
extractor::guidance::DirectionModifier::Left,
extractor::guidance::DirectionModifier::SlightLeft,
extractor::guidance::DirectionModifier::Straight,
extractor::guidance::DirectionModifier::SlightRight,
extractor::guidance::DirectionModifier::Right,
extractor::guidance::DirectionModifier::SharpRight};
return results[modifier];
}
inline bool hasLeftModifier(const extractor::guidance::TurnInstruction instruction)
{
return instruction.direction_modifier == extractor::guidance::DirectionModifier::SharpLeft ||
instruction.direction_modifier == extractor::guidance::DirectionModifier::Left ||
instruction.direction_modifier == extractor::guidance::DirectionModifier::SlightLeft;
}
inline bool hasRightModifier(const extractor::guidance::TurnInstruction instruction)
{
return instruction.direction_modifier == extractor::guidance::DirectionModifier::SharpRight ||
instruction.direction_modifier == extractor::guidance::DirectionModifier::Right ||
instruction.direction_modifier == extractor::guidance::DirectionModifier::SlightRight;
}
inline bool isLeftTurn(const extractor::guidance::TurnInstruction instruction)
{
switch (instruction.type)
{
case TurnType::Merge:
return hasRightModifier(instruction);
default:
return hasLeftModifier(instruction);
}
}
inline bool isRightTurn(const extractor::guidance::TurnInstruction instruction)
{
switch (instruction.type)
{
case TurnType::Merge:
return hasLeftModifier(instruction);
default:
return hasRightModifier(instruction);
}
}
inline DirectionModifier::Enum bearingToDirectionModifier(const double bearing)
{
if (bearing < 135)
{
return extractor::guidance::DirectionModifier::Right;
}
if (bearing <= 225)
{
return extractor::guidance::DirectionModifier::Straight;
}
return extractor::guidance::DirectionModifier::Left;
}
} // namespace guidance
} // namespace extractor
} // namespace osrm
@@ -4,6 +4,7 @@
#include "extractor/guidance/turn_lane_types.hpp"
#include "util/attributes.hpp"
#include "util/typedefs.hpp"
#include <string>
#include <vector>
namespace osrm
@@ -2,6 +2,7 @@
#define OSRM_EXTRACTOR_GUIDANCE_TURN_LANE_HANDLER_HPP_
#include "extractor/guidance/intersection.hpp"
#include "extractor/guidance/toolkit.hpp"
#include "extractor/guidance/turn_analysis.hpp"
#include "extractor/guidance/turn_lane_data.hpp"
#include "extractor/guidance/turn_lane_types.hpp"
@@ -73,7 +74,7 @@ class TurnLaneHandler
std::vector<TurnLaneType::Mask> &turn_lane_masks,
LaneDescriptionMap &lane_description_map,
const TurnAnalysis &turn_analysis,
util::guidance::LaneDataIdMap &id_map);
LaneDataIdMap &id_map);
~TurnLaneHandler();
@@ -90,7 +91,7 @@ class TurnLaneHandler
std::vector<TurnLaneType::Mask> &turn_lane_masks;
LaneDescriptionMap &lane_description_map;
const TurnAnalysis &turn_analysis;
util::guidance::LaneDataIdMap &id_map;
LaneDataIdMap &id_map;
// Find out which scenario we have to handle
TurnLaneScenario deduceScenario(const NodeID at,
@@ -2,6 +2,7 @@
#define OSRM_EXTRACTOR_GUIDANCE_TURN_LANE_MATCHER_HPP_
#include "extractor/guidance/intersection.hpp"
#include "extractor/guidance/toolkit.hpp"
#include "extractor/guidance/turn_instruction.hpp"
#include "extractor/guidance/turn_lane_data.hpp"
@@ -9,6 +10,8 @@
#include "util/guidance/turn_lanes.hpp"
#include "util/node_based_graph.hpp"
#include <unordered_map>
namespace osrm
{
namespace extractor
@@ -44,7 +47,7 @@ Intersection triviallyMatchLanesToTurns(Intersection intersection,
const LaneDataVector &lane_data,
const util::NodeBasedDynamicGraph &node_based_graph,
const LaneDescriptionID lane_string_id,
util::guidance::LaneDataIdMap &lane_data_to_id);
LaneDataIdMap &lane_data_to_id);
} // namespace lanes
} // namespace guidance
@@ -8,9 +8,11 @@
#include <unordered_map>
#include <vector>
#include <boost/assert.hpp>
#include <boost/functional/hash.hpp>
#include "util/json_container.hpp"
#include "util/simple_logger.hpp"
#include "util/typedefs.hpp"
namespace osrm
+17 -17
View File
@@ -43,11 +43,11 @@ struct InternalExtractorEdge
MIN_OSM_NODEID,
0,
0,
false, // forward
false, // backward
false, // roundabout
false, // circular
true, // can be startpoint
false,
false,
false,
false,
true,
TRAVEL_MODE_INACCESSIBLE,
false,
guidance::TurnLaneType::empty,
@@ -62,7 +62,7 @@ struct InternalExtractorEdge
bool forward,
bool backward,
bool roundabout,
bool circular,
bool access_restricted,
bool startpoint,
TravelMode travel_mode,
bool is_split,
@@ -75,7 +75,7 @@ struct InternalExtractorEdge
forward,
backward,
roundabout,
circular,
access_restricted,
startpoint,
travel_mode,
is_split,
@@ -99,11 +99,11 @@ struct InternalExtractorEdge
MIN_OSM_NODEID,
0,
WeightData(),
false, // forward
false, // backward
false, // roundabout
false, // circular
true, // can be startpoint
false,
false,
false,
false,
true,
TRAVEL_MODE_INACCESSIBLE,
false,
INVALID_LANE_DESCRIPTIONID,
@@ -115,11 +115,11 @@ struct InternalExtractorEdge
MAX_OSM_NODEID,
SPECIAL_NODEID,
WeightData(),
false, // forward
false, // backward
false, // roundabout
false, // circular
true, // can be startpoint
false,
false,
false,
false,
true,
TRAVEL_MODE_INACCESSIBLE,
false,
INVALID_LANE_DESCRIPTIONID,
+11 -11
View File
@@ -22,7 +22,7 @@ struct NodeBasedEdge
bool forward,
bool backward,
bool roundabout,
bool circular,
bool access_restricted,
bool startpoint,
TravelMode travel_mode,
bool is_split,
@@ -38,7 +38,7 @@ struct NodeBasedEdge
bool forward : 1;
bool backward : 1;
bool roundabout : 1;
bool circular : 1;
bool access_restricted : 1;
bool startpoint : 1;
bool is_split : 1;
TravelMode travel_mode : 4;
@@ -55,7 +55,7 @@ struct NodeBasedEdgeWithOSM : NodeBasedEdge
bool forward,
bool backward,
bool roundabout,
bool circular,
bool access_restricted,
bool startpoint,
TravelMode travel_mode,
bool is_split,
@@ -70,8 +70,8 @@ struct NodeBasedEdgeWithOSM : NodeBasedEdge
inline NodeBasedEdge::NodeBasedEdge()
: source(SPECIAL_NODEID), target(SPECIAL_NODEID), name_id(0), weight(0), forward(false),
backward(false), roundabout(false), circular(false), startpoint(true), is_split(false),
travel_mode(false), lane_description_id(INVALID_LANE_DESCRIPTIONID)
backward(false), roundabout(false), access_restricted(false), startpoint(true),
is_split(false), travel_mode(false), lane_description_id(INVALID_LANE_DESCRIPTIONID)
{
}
@@ -82,16 +82,16 @@ inline NodeBasedEdge::NodeBasedEdge(NodeID source,
bool forward,
bool backward,
bool roundabout,
bool circular,
bool access_restricted,
bool startpoint,
TravelMode travel_mode,
bool is_split,
const LaneDescriptionID lane_description_id,
guidance::RoadClassification road_classification)
: source(source), target(target), name_id(name_id), weight(weight), forward(forward),
backward(backward), roundabout(roundabout), circular(circular), startpoint(startpoint),
is_split(is_split), travel_mode(travel_mode), lane_description_id(lane_description_id),
road_classification(std::move(road_classification))
backward(backward), roundabout(roundabout), access_restricted(access_restricted),
startpoint(startpoint), is_split(is_split), travel_mode(travel_mode),
lane_description_id(lane_description_id), road_classification(std::move(road_classification))
{
}
@@ -119,7 +119,7 @@ inline NodeBasedEdgeWithOSM::NodeBasedEdgeWithOSM(OSMNodeID source,
bool forward,
bool backward,
bool roundabout,
bool circular,
bool access_restricted,
bool startpoint,
TravelMode travel_mode,
bool is_split,
@@ -132,7 +132,7 @@ inline NodeBasedEdgeWithOSM::NodeBasedEdgeWithOSM(OSMNodeID source,
forward,
backward,
roundabout,
circular,
access_restricted,
startpoint,
travel_mode,
is_split,
+13 -9
View File
@@ -10,7 +10,6 @@
#include <boost/filesystem/fstream.hpp>
#include <boost/spirit/include/qi.hpp>
#include <boost/spirit/include/qi_int.hpp>
#include <storage/io.hpp>
#include <iterator>
#include <unordered_map>
@@ -44,14 +43,20 @@ class RasterGrid
ydim = _ydim;
_data.reserve(ydim * xdim);
storage::io::FileReader file_reader(filepath, storage::io::FileReader::HasNoFingerprint);
boost::filesystem::ifstream stream(filepath, std::ios::binary);
if (!stream)
{
throw util::exception("Unable to open raster file.");
}
stream.seekg(0, std::ios_base::end);
std::string buffer;
buffer.resize(file_reader.Size());
buffer.resize(static_cast<std::size_t>(stream.tellg()));
stream.seekg(0, std::ios_base::beg);
BOOST_ASSERT(buffer.size() > 1);
file_reader.ReadInto(&buffer[0], buffer.size());
stream.read(&buffer[0], static_cast<std::streamsize>(buffer.size()));
boost::algorithm::trim(buffer);
@@ -66,14 +71,13 @@ class RasterGrid
}
catch (std::exception const &ex)
{
throw util::exception("Failed to read from raster source " + filepath.string() + ": " +
ex.what() + SOURCE_REF);
throw util::exception(
std::string("Failed to read from raster source with exception: ") + ex.what());
}
if (!r || itr != end)
{
throw util::exception("Failed to parse raster source: " + filepath.string() +
SOURCE_REF);
throw util::exception("Failed to parse raster source correctly.");
}
}
+4 -4
View File
@@ -8,7 +8,7 @@
#include "util/typedefs.hpp"
#include "util/integer_range.hpp"
#include "util/log.hpp"
#include "util/simple_logger.hpp"
#include "util/std_hash.hpp"
#include "util/timing_util.hpp"
@@ -146,8 +146,8 @@ template <typename GraphT> class TarjanSCC
if (size_of_current_component > 1000)
{
util::Log() << "large component [" << component_index
<< "]=" << size_of_current_component;
util::SimpleLogger().Write() << "large component [" << component_index
<< "]=" << size_of_current_component;
}
++component_index;
@@ -158,7 +158,7 @@ template <typename GraphT> class TarjanSCC
}
TIMER_STOP(SCC_RUN);
util::Log() << "SCC run took: " << TIMER_MSEC(SCC_RUN) / 1000. << "s";
util::SimpleLogger().Write() << "SCC run took: " << TIMER_MSEC(SCC_RUN) / 1000. << "s";
size_one_counter = std::count_if(component_size_vector.begin(),
component_size_vector.end(),
+4 -3
View File
@@ -6,7 +6,7 @@
#include "server/service_handler.hpp"
#include "util/integer_range.hpp"
#include "util/log.hpp"
#include "util/simple_logger.hpp"
#include <boost/asio.hpp>
#include <boost/bind.hpp>
@@ -36,7 +36,8 @@ class Server
static std::shared_ptr<Server>
CreateServer(std::string &ip_address, int ip_port, unsigned requested_num_threads)
{
util::Log() << "http 1.1 compression handled by zlib version " << zlibVersion();
util::SimpleLogger().Write() << "http 1.1 compression handled by zlib version "
<< zlibVersion();
const unsigned hardware_threads = std::max(1u, std::thread::hardware_concurrency());
const unsigned real_num_threads = std::min(hardware_threads, requested_num_threads);
return std::make_shared<Server>(ip_address, ip_port, real_num_threads);
@@ -61,7 +62,7 @@ class Server
acceptor.bind(endpoint);
acceptor.listen();
util::Log() << "Listening on: " << acceptor.local_endpoint();
util::SimpleLogger().Write() << "Listening on: " << acceptor.local_endpoint();
acceptor.async_accept(
new_connection->socket(),
+1 -1
View File
@@ -5,7 +5,7 @@
#include "osrm/osrm.hpp"
#include "util/coordinate.hpp"
#include <mapbox/variant.hpp>
#include <variant/variant.hpp>
#include <string>
#include <vector>
+195 -222
View File
@@ -1,17 +1,17 @@
#ifndef OSRM_STORAGE_IO_HPP_
#define OSRM_STORAGE_IO_HPP_
#include "util/exception.hpp"
#include "util/exception_utils.hpp"
#include "contractor/query_edge.hpp"
#include "extractor/extractor.hpp"
#include "extractor/original_edge_data.hpp"
#include "extractor/query_node.hpp"
#include "util/fingerprint.hpp"
#include "util/log.hpp"
#include "util/simple_logger.hpp"
#include "util/static_graph.hpp"
#include <boost/filesystem/fstream.hpp>
#include <boost/iostreams/seek.hpp>
#include <cstring>
#include <tuple>
#include <type_traits>
namespace osrm
{
@@ -20,228 +20,201 @@ namespace storage
namespace io
{
class FileReader
// Reads the count of elements that is written in the file header and returns the number
inline std::uint64_t readElementCount(boost::filesystem::ifstream &input_stream)
{
private:
const boost::filesystem::path filepath;
boost::filesystem::ifstream input_stream;
std::uint64_t number_of_elements = 0;
input_stream.read((char *)&number_of_elements, sizeof(std::uint64_t));
return number_of_elements;
}
public:
class LineWrapper : public std::string
{
friend std::istream &operator>>(std::istream &is, LineWrapper &line)
{
return std::getline(is, line);
}
};
auto GetLineIteratorBegin() { return std::istream_iterator<LineWrapper>(input_stream); }
auto GetLineIteratorEnd() { return std::istream_iterator<LineWrapper>(); }
// To make function calls consistent, this function returns the fixed number of properties
inline std::size_t readPropertiesCount() { return 1; }
enum FingerprintFlag
{
VerifyFingerprint,
HasNoFingerprint
};
FileReader(const std::string &filename, const FingerprintFlag flag)
: FileReader(boost::filesystem::path(filename), flag)
{
}
FileReader(const boost::filesystem::path &filepath_, const FingerprintFlag flag)
: filepath(filepath_)
{
input_stream.open(filepath, std::ios::binary);
if (!input_stream)
throw util::exception("Error opening " + filepath.string());
if (flag == VerifyFingerprint && !ReadAndCheckFingerprint())
{
throw util::exception("Fingerprint mismatch in " + filepath_.string() + SOURCE_REF);
}
}
/* Read count objects of type T into pointer dest */
template <typename T> void ReadInto(T *dest, const std::size_t count)
{
#if not defined __GNUC__ or __GNUC__ > 4
static_assert(std::is_trivially_copyable<T>::value,
"bytewise reading requires trivially copyable type");
#endif
if (count == 0)
return;
const auto &result = input_stream.read(reinterpret_cast<char *>(dest), count * sizeof(T));
if (!result)
{
if (result.eof())
{
throw util::exception("Error reading from " + filepath.string() +
": Unexpected end of file " + SOURCE_REF);
}
throw util::exception("Error reading from " + filepath.string() + " " + SOURCE_REF);
}
}
template <typename T> void ReadInto(std::vector<T> &target)
{
ReadInto(target.data(), target.size());
}
template <typename T> void ReadInto(T &target) { ReadInto(&target, 1); }
template <typename T> T ReadOne()
{
T tmp;
ReadInto(tmp);
return tmp;
}
template <typename T> void Skip(const std::size_t element_count)
{
boost::iostreams::seek(input_stream, element_count * sizeof(T), BOOST_IOS::cur);
}
/*******************************************/
std::uint32_t ReadElementCount32() { return ReadOne<std::uint32_t>(); }
std::uint64_t ReadElementCount64() { return ReadOne<std::uint64_t>(); }
template <typename T> void DeserializeVector(std::vector<T> &data)
{
const auto count = ReadElementCount64();
data.resize(count);
ReadInto(data.data(), count);
}
bool ReadAndCheckFingerprint()
{
auto fingerprint = ReadOne<util::FingerPrint>();
const auto valid = util::FingerPrint::GetValid();
// compare the compilation state stored in the fingerprint
return valid.IsMagicNumberOK(fingerprint) && valid.TestContractor(fingerprint) &&
valid.TestGraphUtil(fingerprint) && valid.TestRTree(fingerprint) &&
valid.TestQueryObjects(fingerprint);
}
std::size_t Size()
{
auto current_pos = input_stream.tellg();
input_stream.seekg(0, input_stream.end);
auto length = input_stream.tellg();
input_stream.seekg(current_pos, input_stream.beg);
return length;
}
std::vector<std::string> ReadLines()
{
std::vector<std::string> result;
std::string thisline;
try
{
while (std::getline(input_stream, thisline))
{
result.push_back(thisline);
}
}
catch (const std::ios_base::failure &e)
{
// EOF is OK here, everything else, re-throw
if (!input_stream.eof())
throw;
}
return result;
}
std::string ReadLine()
{
std::string thisline;
try
{
std::getline(input_stream, thisline);
}
catch (const std::ios_base::failure & /*e*/)
{
// EOF is OK here, everything else, re-throw
if (!input_stream.eof())
throw;
}
return thisline;
}
};
class FileWriter
// Returns the number of bytes in a file
inline std::size_t readNumberOfBytes(boost::filesystem::ifstream &input_stream)
{
private:
const boost::filesystem::path filepath;
boost::filesystem::ofstream output_stream;
input_stream.seekg(0, input_stream.end);
auto length = input_stream.tellg();
input_stream.seekg(0, input_stream.beg);
return length;
}
public:
enum FingerprintFlag
{
GenerateFingerprint,
HasNoFingerprint
};
FileWriter(const std::string &filename, const FingerprintFlag flag)
: FileWriter(boost::filesystem::path(filename), flag)
{
}
FileWriter(const boost::filesystem::path &filepath_, const FingerprintFlag flag)
: filepath(filepath_)
{
output_stream.open(filepath, std::ios::binary);
if (!output_stream)
throw util::exception("Error opening " + filepath.string());
if (flag == GenerateFingerprint)
{
WriteFingerprint();
}
}
/* Write count objects of type T from pointer src to output stream */
template <typename T> bool WriteFrom(T *src, const std::size_t count)
{
#if not defined __GNUC__ or __GNUC__ > 4
static_assert(std::is_trivially_copyable<T>::value,
"bytewise writing requires trivially copyable type");
#endif
if (count == 0)
return true;
const auto &result = output_stream.write(reinterpret_cast<char *>(src), count * sizeof(T));
if (!result)
{
throw util::exception("Error writing to " + filepath.string());
}
return static_cast<bool>(output_stream);
}
template <typename T> bool WriteFrom(T &target) { return WriteFrom(&target, 1); }
template <typename T> bool WriteOne(T tmp) { return WriteFrom(tmp); }
bool WriteElementCount32(const std::uint32_t count) { return WriteOne<std::uint32_t>(count); }
bool WriteElementCount64(const std::uint64_t count) { return WriteOne<std::uint64_t>(count); }
template <typename T> bool SerializeVector(std::vector<T> &data)
{
const auto count = data.size();
WriteElementCount64(count);
return WriteFrom(data.data(), count);
}
bool WriteFingerprint()
{
const auto fingerprint = util::FingerPrint::GetValid();
return WriteOne(fingerprint);
}
#pragma pack(push, 1)
struct HSGRHeader
{
std::uint32_t checksum;
std::uint64_t number_of_nodes;
std::uint64_t number_of_edges;
};
#pragma pack(pop)
static_assert(sizeof(HSGRHeader) == 20, "HSGRHeader is not packed");
// Reads the checksum, number of nodes and number of edges written in the header file of a `.hsgr`
// file and returns them in a HSGRHeader struct
inline HSGRHeader readHSGRHeader(boost::filesystem::ifstream &input_stream)
{
const util::FingerPrint fingerprint_valid = util::FingerPrint::GetValid();
util::FingerPrint fingerprint_loaded;
input_stream.read(reinterpret_cast<char *>(&fingerprint_loaded), sizeof(util::FingerPrint));
if (!fingerprint_loaded.TestGraphUtil(fingerprint_valid))
{
util::SimpleLogger().Write(logWARNING) << ".hsgr was prepared with different build.\n"
"Reprocess to get rid of this warning.";
}
HSGRHeader header;
input_stream.read(reinterpret_cast<char *>(&header.checksum), sizeof(header.checksum));
input_stream.read(reinterpret_cast<char *>(&header.number_of_nodes),
sizeof(header.number_of_nodes));
input_stream.read(reinterpret_cast<char *>(&header.number_of_edges),
sizeof(header.number_of_edges));
BOOST_ASSERT_MSG(0 != header.number_of_nodes, "number of nodes is zero");
// number of edges can be zero, this is the case in a few test fixtures
return header;
}
// Reads the graph data of a `.hsgr` file into memory
// Needs to be called after readHSGRHeader() to get the correct offset in the stream
using NodeT = typename util::StaticGraph<contractor::QueryEdge::EdgeData>::NodeArrayEntry;
using EdgeT = typename util::StaticGraph<contractor::QueryEdge::EdgeData>::EdgeArrayEntry;
inline void readHSGR(boost::filesystem::ifstream &input_stream,
NodeT *node_buffer,
const std::uint64_t number_of_nodes,
EdgeT *edge_buffer,
const std::uint64_t number_of_edges)
{
BOOST_ASSERT(node_buffer);
BOOST_ASSERT(edge_buffer);
input_stream.read(reinterpret_cast<char *>(node_buffer), number_of_nodes * sizeof(NodeT));
input_stream.read(reinterpret_cast<char *>(edge_buffer), number_of_edges * sizeof(EdgeT));
}
// Loads properties from a `.properties` file into memory
inline void readProperties(boost::filesystem::ifstream &properties_stream,
extractor::ProfileProperties *properties,
const std::size_t properties_size)
{
BOOST_ASSERT(properties);
properties_stream.read(reinterpret_cast<char *>(properties), properties_size);
}
// Reads the timestamp in a `.timestamp` file
// Use readNumberOfBytes() beforehand to get the length of the file
inline void readTimestamp(boost::filesystem::ifstream &timestamp_input_stream,
char *timestamp,
const std::size_t timestamp_length)
{
BOOST_ASSERT(timestamp);
timestamp_input_stream.read(timestamp, timestamp_length * sizeof(char));
}
// Loads datasource_indexes from .datasource_indexes into memory
// Needs to be called after readElementCount() to get the correct offset in the stream
inline void readDatasourceIndexes(boost::filesystem::ifstream &datasource_indexes_input_stream,
uint8_t *datasource_buffer,
const std::uint64_t number_of_datasource_indexes)
{
BOOST_ASSERT(datasource_buffer);
datasource_indexes_input_stream.read(reinterpret_cast<char *>(datasource_buffer),
number_of_datasource_indexes * sizeof(std::uint8_t));
}
// Loads edge data from .edge files into memory which includes its
// geometry, name ID, turn instruction, lane data ID, travel mode, entry class ID
// Needs to be called after readElementCount() to get the correct offset in the stream
inline void readEdges(boost::filesystem::ifstream &edges_input_stream,
GeometryID *geometry_list,
NameID *name_id_list,
extractor::guidance::TurnInstruction *turn_instruction_list,
LaneDataID *lane_data_id_list,
extractor::TravelMode *travel_mode_list,
EntryClassID *entry_class_id_list,
util::guidance::TurnBearing *pre_turn_bearing_list,
util::guidance::TurnBearing *post_turn_bearing_list,
const std::uint64_t number_of_edges)
{
BOOST_ASSERT(geometry_list);
BOOST_ASSERT(name_id_list);
BOOST_ASSERT(turn_instruction_list);
BOOST_ASSERT(lane_data_id_list);
BOOST_ASSERT(travel_mode_list);
BOOST_ASSERT(entry_class_id_list);
extractor::OriginalEdgeData current_edge_data;
for (std::uint64_t i = 0; i < number_of_edges; ++i)
{
edges_input_stream.read((char *)&(current_edge_data), sizeof(extractor::OriginalEdgeData));
geometry_list[i] = current_edge_data.via_geometry;
name_id_list[i] = current_edge_data.name_id;
turn_instruction_list[i] = current_edge_data.turn_instruction;
lane_data_id_list[i] = current_edge_data.lane_data_id;
travel_mode_list[i] = current_edge_data.travel_mode;
entry_class_id_list[i] = current_edge_data.entry_classid;
pre_turn_bearing_list[i] = current_edge_data.pre_turn_bearing;
post_turn_bearing_list[i] = current_edge_data.post_turn_bearing;
}
}
// Loads coordinates and OSM node IDs from .nodes files into memory
// Needs to be called after readElementCount() to get the correct offset in the stream
template <typename OSMNodeIDVectorT>
void readNodes(boost::filesystem::ifstream &nodes_input_stream,
util::Coordinate *coordinate_list,
OSMNodeIDVectorT &osmnodeid_list,
const std::uint64_t number_of_coordinates)
{
BOOST_ASSERT(coordinate_list);
extractor::QueryNode current_node;
for (std::uint64_t i = 0; i < number_of_coordinates; ++i)
{
nodes_input_stream.read((char *)&current_node, sizeof(extractor::QueryNode));
coordinate_list[i] = util::Coordinate(current_node.lon, current_node.lat);
osmnodeid_list.push_back(current_node.node_id);
BOOST_ASSERT(coordinate_list[i].IsValid());
}
}
// Reads datasource names out of .datasource_names files and metadata such as
// the length and offset of each name
struct DatasourceNamesData
{
std::vector<char> names;
std::vector<std::size_t> offsets;
std::vector<std::size_t> lengths;
};
inline DatasourceNamesData
readDatasourceNames(boost::filesystem::ifstream &datasource_names_input_stream)
{
DatasourceNamesData datasource_names_data;
std::string name;
while (std::getline(datasource_names_input_stream, name))
{
datasource_names_data.offsets.push_back(datasource_names_data.names.size());
datasource_names_data.lengths.push_back(name.size());
std::copy(name.c_str(),
name.c_str() + name.size(),
std::back_inserter(datasource_names_data.names));
}
return datasource_names_data;
}
// Loads ram indexes of R-Trees from `.ramIndex` files into memory
// Needs to be called after readElementCount() to get the correct offset in the stream
// template <bool UseSharedMemory>
// NB Cannot be written without templated type because of cyclic depencies between
// `static_rtree.hpp` and `io.hpp`
template <typename RTreeNodeT>
void readRamIndex(boost::filesystem::ifstream &ram_index_input_stream,
RTreeNodeT *rtree_buffer,
const std::uint64_t tree_size)
{
BOOST_ASSERT(rtree_buffer);
ram_index_input_stream.read(reinterpret_cast<char *>(rtree_buffer),
sizeof(RTreeNodeT) * tree_size);
}
}
}
}
-171
View File
@@ -1,171 +0,0 @@
#ifndef OSRM_STORAGE_SERIALIZATION_HPP_
#define OSRM_STORAGE_SERIALIZATION_HPP_
#include "contractor/query_edge.hpp"
#include "extractor/extractor.hpp"
#include "extractor/original_edge_data.hpp"
#include "extractor/query_node.hpp"
#include "storage/io.hpp"
#include "util/exception.hpp"
#include "util/fingerprint.hpp"
#include "util/log.hpp"
#include "util/static_graph.hpp"
#include <boost/filesystem/fstream.hpp>
#include <boost/iostreams/seek.hpp>
#include <cerrno>
#include <cstring>
#include <tuple>
#include <type_traits>
namespace osrm
{
namespace storage
{
namespace serialization
{
// To make function calls consistent, this function returns the fixed number of properties
inline std::size_t readPropertiesCount() { return 1; }
struct HSGRHeader
{
std::uint32_t checksum;
std::uint64_t number_of_nodes;
std::uint64_t number_of_edges;
};
// Reads the checksum, number of nodes and number of edges written in the header file of a `.hsgr`
// file and returns them in a HSGRHeader struct
inline HSGRHeader readHSGRHeader(io::FileReader &input_file)
{
const util::FingerPrint fingerprint_valid = util::FingerPrint::GetValid();
const auto fingerprint_loaded = input_file.ReadOne<util::FingerPrint>();
if (!fingerprint_loaded.TestGraphUtil(fingerprint_valid))
{
util::Log(logWARNING) << ".hsgr was prepared with different build.\n"
"Reprocess to get rid of this warning.";
}
HSGRHeader header;
input_file.ReadInto(header.checksum);
input_file.ReadInto(header.number_of_nodes);
input_file.ReadInto(header.number_of_edges);
// If we have edges, then we must have nodes.
// However, there can be nodes with no edges (some test cases create this)
BOOST_ASSERT_MSG(header.number_of_edges == 0 || header.number_of_nodes > 0,
"edges exist, but there are no nodes");
return header;
}
// Reads the graph data of a `.hsgr` file into memory
// Needs to be called after readHSGRHeader() to get the correct offset in the stream
using NodeT = typename util::StaticGraph<contractor::QueryEdge::EdgeData>::NodeArrayEntry;
using EdgeT = typename util::StaticGraph<contractor::QueryEdge::EdgeData>::EdgeArrayEntry;
inline void readHSGR(io::FileReader &input_file,
NodeT *node_buffer,
const std::uint64_t number_of_nodes,
EdgeT *edge_buffer,
const std::uint64_t number_of_edges)
{
BOOST_ASSERT(node_buffer);
BOOST_ASSERT(edge_buffer);
input_file.ReadInto(node_buffer, number_of_nodes);
input_file.ReadInto(edge_buffer, number_of_edges);
}
// Loads datasource_indexes from .datasource_indexes into memory
// Needs to be called after readElementCount() to get the correct offset in the stream
inline void readDatasourceIndexes(io::FileReader &datasource_indexes_file,
uint8_t *datasource_buffer,
const std::uint64_t number_of_datasource_indexes)
{
BOOST_ASSERT(datasource_buffer);
datasource_indexes_file.ReadInto(datasource_buffer, number_of_datasource_indexes);
}
// Loads edge data from .edge files into memory which includes its
// geometry, name ID, turn instruction, lane data ID, travel mode, entry class ID
// Needs to be called after readElementCount() to get the correct offset in the stream
inline void readEdges(io::FileReader &edges_input_file,
GeometryID *geometry_list,
NameID *name_id_list,
extractor::guidance::TurnInstruction *turn_instruction_list,
LaneDataID *lane_data_id_list,
extractor::TravelMode *travel_mode_list,
EntryClassID *entry_class_id_list,
util::guidance::TurnBearing *pre_turn_bearing_list,
util::guidance::TurnBearing *post_turn_bearing_list,
const std::uint64_t number_of_edges)
{
BOOST_ASSERT(geometry_list);
BOOST_ASSERT(name_id_list);
BOOST_ASSERT(turn_instruction_list);
BOOST_ASSERT(lane_data_id_list);
BOOST_ASSERT(travel_mode_list);
BOOST_ASSERT(entry_class_id_list);
extractor::OriginalEdgeData current_edge_data;
for (std::uint64_t i = 0; i < number_of_edges; ++i)
{
edges_input_file.ReadInto(current_edge_data);
geometry_list[i] = current_edge_data.via_geometry;
name_id_list[i] = current_edge_data.name_id;
turn_instruction_list[i] = current_edge_data.turn_instruction;
lane_data_id_list[i] = current_edge_data.lane_data_id;
travel_mode_list[i] = current_edge_data.travel_mode;
entry_class_id_list[i] = current_edge_data.entry_classid;
pre_turn_bearing_list[i] = current_edge_data.pre_turn_bearing;
post_turn_bearing_list[i] = current_edge_data.post_turn_bearing;
}
}
// Loads coordinates and OSM node IDs from .nodes files into memory
// Needs to be called after readElementCount() to get the correct offset in the stream
template <typename OSMNodeIDVectorT>
void readNodes(io::FileReader &nodes_file,
util::Coordinate *coordinate_list,
OSMNodeIDVectorT &osmnodeid_list,
const std::uint64_t number_of_coordinates)
{
BOOST_ASSERT(coordinate_list);
extractor::QueryNode current_node;
for (std::uint64_t i = 0; i < number_of_coordinates; ++i)
{
nodes_file.ReadInto(current_node);
coordinate_list[i] = util::Coordinate(current_node.lon, current_node.lat);
osmnodeid_list.push_back(current_node.node_id);
BOOST_ASSERT(coordinate_list[i].IsValid());
}
}
// Reads datasource names out of .datasource_names files and metadata such as
// the length and offset of each name
struct DatasourceNamesData
{
std::vector<char> names;
std::vector<std::size_t> offsets;
std::vector<std::size_t> lengths;
};
inline DatasourceNamesData readDatasourceNames(io::FileReader &datasource_names_file)
{
DatasourceNamesData datasource_names_data;
std::vector<std::string> lines = datasource_names_file.ReadLines();
for (const auto &name : lines)
{
datasource_names_data.offsets.push_back(datasource_names_data.names.size());
datasource_names_data.lengths.push_back(name.size());
std::copy(name.c_str(),
name.c_str() + name.size(),
std::back_inserter(datasource_names_data.names));
}
return datasource_names_data;
}
}
}
}
#endif

Some files were not shown because too many files have changed in this diff Show More