Compare commits
63 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
| 1cd1d187d2 | |||
| c1ad275e71 | |||
| 6bae070091 | |||
| 3687b6cb4b | |||
| 196ed9eb46 | |||
| 37c941dff3 | |||
| 40a428d49f | |||
| 48eeef2d30 | |||
| c34520f3a4 | |||
| 36db965c39 | |||
| 4e81764ce2 | |||
| 1e9f983289 | |||
| 2e404c60f4 | |||
| 40857aae61 | |||
| a64145b712 | |||
| 945f6da85e | |||
| 76d5d054cb | |||
| 20cfa159ec | |||
| 3ff1a4263d | |||
| 3141eb5dce | |||
| 75d6f59026 | |||
| ae42ce7017 | |||
| e9c9c87bbc | |||
| 8a6dba46b1 | |||
| 93299d6651 | |||
| f34320a89b | |||
| a17b07bc4c | |||
| 3a01ba52ef | |||
| d796c66990 | |||
| 80b705e997 | |||
| 7069af3e20 | |||
| 209a926b45 | |||
| 71e0c7a3cf | |||
| b88d96f07d | |||
| 46f75c3d92 | |||
| 3b8e5cec88 | |||
| a420169109 | |||
| a8db269fd5 | |||
| a5efcfdede | |||
| 1ecc913fc2 | |||
| 08eb3b11bc | |||
| b59d9a2f27 | |||
| e9a5e32330 | |||
| be9bdfa47e | |||
| 153e934ed4 | |||
| 4757c96d9a | |||
| 1efc527281 | |||
| 468b59c53d | |||
| 15426975b6 | |||
| bbcf343e40 | |||
| f0d3cf4e43 | |||
| 4c965b9f44 | |||
| e5143247c2 | |||
| 3a676183b2 | |||
| 64265926a4 | |||
| df2d4daad3 | |||
| fd0d79e17b | |||
| 84ce97a31e | |||
| 7e0c9f7340 | |||
| 917a36eaee | |||
| 7620d419c6 | |||
| 50c90b29d2 | |||
| 0e77cf53f6 |
@@ -1,4 +1,5 @@
|
||||
{
|
||||
"plugins": ["transform-class-properties"],
|
||||
"presets": [
|
||||
"stage-0",
|
||||
"es2015",
|
||||
|
||||
@@ -46,6 +46,7 @@ Thumbs.db
|
||||
|
||||
# build related files #
|
||||
#######################
|
||||
/_build*
|
||||
/build/
|
||||
/example/build/
|
||||
/test/data/monaco*
|
||||
|
||||
+15
@@ -0,0 +1,15 @@
|
||||
*
|
||||
!README.md
|
||||
!CHANGELOG.md
|
||||
!CONTRIBUTING.MD
|
||||
!LICENCE.TXT
|
||||
!package.json
|
||||
!package-lock.json
|
||||
!yarn.lock
|
||||
!docs
|
||||
!example
|
||||
!taginfo.json
|
||||
!lib/*.js
|
||||
!profiles/*
|
||||
!profiles/lib/*
|
||||
!profiles/examples/*
|
||||
+1
-1
@@ -301,7 +301,7 @@ before_install:
|
||||
- mkdir -p ${CMAKE_DIR}
|
||||
- travis_retry wget --quiet -O - ${CMAKE_URL} | tar --strip-components=1 -xz -C ${CMAKE_DIR} || travis_terminate 1
|
||||
- export PATH=${CMAKE_DIR}/bin:${PATH}
|
||||
- ${MASON} install tbb 2017_20161128 && export LD_LIBRARY_PATH=$(${MASON} prefix tbb 2017_20161128)/lib/:${LD_LIBRARY_PATH}
|
||||
- ${MASON} install tbb 2017_U7 && export LD_LIBRARY_PATH=$(${MASON} prefix tbb 2017_U7)/lib/:${LD_LIBRARY_PATH}
|
||||
- ${MASON} install ccache ${CCACHE_VERSION} && export PATH=$(${MASON} prefix ccache ${CCACHE_VERSION})/bin:${PATH}
|
||||
- |
|
||||
if [[ ! -z ${CLANG_VERSION} ]]; then
|
||||
|
||||
@@ -1,3 +1,24 @@
|
||||
# 5.11.0
|
||||
- Changes from 5.10:
|
||||
- Features
|
||||
- BREAKING: Added support for conditional via-way restrictions. This features changes the file format of osrm.restrictions and requires re-extraction
|
||||
- Internals
|
||||
- BREAKING: Traffic signals will no longer be represented as turns internally. This requires re-processing of data but enables via-way turn restrictions across highway=traffic_signals
|
||||
- Additional checks for empty segments when loading traffic data files
|
||||
- Tunes the constants for turns in sharp curves just a tiny bit to circumvent a mix-up in fork directions at a specific intersection (https://github.com/Project-OSRM/osrm-backend/issues/4331)
|
||||
- Infrastructure
|
||||
- Refactor datafacade to make implementing additional DataFacades simpler
|
||||
- Bugfixes
|
||||
- API docs are now buildable again
|
||||
- Suppress unnecessary extra turn instruction when exiting a motorway via a motorway_link onto a primary road (https://github.com/Project-OSRM/osrm-backend/issues/4348 scenario 4)
|
||||
- Suppress unnecessary extra turn instruction when taking a tertiary_link road from a teritary onto a residential road (https://github.com/Project-OSRM/osrm-backend/issues/4348 scenario 2)
|
||||
- Various MSVC++ build environment fixes
|
||||
- Avoid a bug that crashes GCC6
|
||||
- Re-include .npmignore to slim down published modules
|
||||
- Fix a pre-processing bug where incorrect directions could be issued when two turns would have similar instructions and we tried to give them distinct values (https://github.com/Project-OSRM/osrm-backend/pull/4375)
|
||||
- The entry bearing for correct the cardinality of a direction value (https://github.com/Project-OSRM/osrm-backend/pull/4353
|
||||
- Change timezones in West Africa to the WAT zone so they're recognized on the Windows platform
|
||||
|
||||
# 5.10.0
|
||||
- Changes from 5.9:
|
||||
- Profiles:
|
||||
@@ -17,6 +38,7 @@
|
||||
- Guidance: add support for throughabouts
|
||||
- Bugfixes
|
||||
- Properly save/retrieve datasource annotations for road segments ([#4346](https://github.com/Project-OSRM/osrm-backend/issues/4346)
|
||||
- Fix conditional restriction grammer parsing so it works for single-day-of-week restrictions ([#4357](https://github.com/Project-OSRM/osrm-backend/pull/4357))
|
||||
- Algorithm)
|
||||
- BREAKING: the file format requires re-processing due to the changes on via-ways
|
||||
- Added support for via-way restrictions
|
||||
|
||||
+18
-17
@@ -60,7 +60,7 @@ if (POLICY CMP0048)
|
||||
endif()
|
||||
project(OSRM C CXX)
|
||||
set(OSRM_VERSION_MAJOR 5)
|
||||
set(OSRM_VERSION_MINOR 10)
|
||||
set(OSRM_VERSION_MINOR 11)
|
||||
set(OSRM_VERSION_PATCH 0)
|
||||
set(OSRM_VERSION "${OSRM_VERSION_MAJOR}.${OSRM_VERSION_MINOR}.${OSRM_VERSION_PATCH}")
|
||||
|
||||
@@ -102,11 +102,11 @@ if(WIN32 AND MSVC_VERSION LESS 1900)
|
||||
endif()
|
||||
|
||||
# Strictly require GCC>=4.9 and Clang>=3.4 - GCC 4.8 is already too old for C++14.
|
||||
if(CMAKE_CXX_COMPILER_ID STREQUAL "GNU")
|
||||
if(CMAKE_CXX_COMPILER_ID MATCHES "GNU")
|
||||
if(CMAKE_CXX_COMPILER_VERSION VERSION_LESS 4.9)
|
||||
message(FATAL_ERROR "GCC>=4.9 required. In case you are on Ubuntu upgrade via ppa:ubuntu-toolchain-r/test")
|
||||
endif()
|
||||
elseif(CMAKE_CXX_COMPILER_ID STREQUAL "Clang")
|
||||
elseif(CMAKE_CXX_COMPILER_ID MATCHES "Clang")
|
||||
if(CMAKE_CXX_COMPILER_VERSION VERSION_LESS 3.4)
|
||||
message(FATAL_ERROR "Clang>=3.4 required. In case you are on Ubuntu upgrade via http://apt.llvm.org")
|
||||
endif()
|
||||
@@ -182,7 +182,7 @@ endif()
|
||||
|
||||
# Disable LTO when mason+gcc is detected before testing for / setting any flags.
|
||||
# Mason builds libraries with Clang, mixing does not work in the context of lto.
|
||||
if(ENABLE_MASON AND CMAKE_CXX_COMPILER_ID STREQUAL "GNU" AND ENABLE_LTO)
|
||||
if(ENABLE_MASON AND CMAKE_CXX_COMPILER_ID MATCHES "GNU" AND ENABLE_LTO)
|
||||
set(ENABLE_LTO OFF)
|
||||
message(WARNING "Mason and GCC's LTO not work together. Disabling LTO.")
|
||||
endif()
|
||||
@@ -211,9 +211,9 @@ endif()
|
||||
if(CMAKE_BUILD_TYPE MATCHES Debug OR CMAKE_BUILD_TYPE MATCHES RelWithDebInfo)
|
||||
message(STATUS "Configuring debug mode flags")
|
||||
set(ENABLE_ASSERTIONS ON)
|
||||
if(NOT ${CMAKE_CXX_COMPILER_ID} STREQUAL "MSVC")
|
||||
if(NOT CMAKE_CXX_COMPILER_ID MATCHES "MSVC")
|
||||
set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -fno-inline -fno-omit-frame-pointer")
|
||||
if("${CMAKE_CXX_COMPILER_ID}" STREQUAL "GNU")
|
||||
if(CMAKE_CXX_COMPILER_ID MATCHES "GNU")
|
||||
if (CMAKE_BUILD_TYPE MATCHES Debug)
|
||||
set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -Og -ggdb")
|
||||
else()
|
||||
@@ -232,7 +232,7 @@ if(CMAKE_BUILD_TYPE MATCHES Release OR CMAKE_BUILD_TYPE MATCHES MinRelSize OR CM
|
||||
if(ENABLE_LTO AND LTO_AVAILABLE)
|
||||
set(OLD_CXX_FLAGS ${CMAKE_CXX_FLAGS})
|
||||
# GCC in addition allows parallelizing LTO
|
||||
if("${CMAKE_CXX_COMPILER_ID}" STREQUAL "GNU")
|
||||
if(CMAKE_CXX_COMPILER_ID MATCHES "GNU")
|
||||
include(ProcessorCount)
|
||||
ProcessorCount(NPROC)
|
||||
set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -flto=${NPROC}")
|
||||
@@ -255,7 +255,7 @@ if(CMAKE_BUILD_TYPE MATCHES Release OR CMAKE_BUILD_TYPE MATCHES MinRelSize OR CM
|
||||
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
|
||||
if(CMAKE_CXX_COMPILER_ID MATCHES "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)
|
||||
@@ -271,7 +271,7 @@ if(CMAKE_BUILD_TYPE MATCHES Release OR CMAKE_BUILD_TYPE MATCHES MinRelSize OR CM
|
||||
endif()
|
||||
|
||||
# Same for clang LTO requires their own toolchain
|
||||
if("${CMAKE_CXX_COMPILER_ID}" STREQUAL "Clang")
|
||||
if(CMAKE_CXX_COMPILER_ID MATCHES "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")
|
||||
@@ -285,7 +285,7 @@ if(CMAKE_BUILD_TYPE MATCHES Release OR CMAKE_BUILD_TYPE MATCHES MinRelSize OR CM
|
||||
endif()
|
||||
endif()
|
||||
|
||||
if("${CMAKE_CXX_COMPILER_ID}" STREQUAL "GNU" AND "${CMAKE_CXX_COMPILER_VERSION}" VERSION_LESS "4.9.0")
|
||||
if(CMAKE_CXX_COMPILER_ID MATCHES "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)
|
||||
@@ -315,9 +315,9 @@ if (ENABLE_SANITIZER)
|
||||
endif()
|
||||
|
||||
# Configuring compilers
|
||||
if(${CMAKE_CXX_COMPILER_ID} STREQUAL "Clang")
|
||||
if(CMAKE_CXX_COMPILER_ID MATCHES "Clang")
|
||||
set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -Wall -Wextra -pedantic -Wuninitialized -Wunreachable-code -Wstrict-overflow=2 -U_FORTIFY_SOURCE -D_FORTIFY_SOURCE=2 -fPIC -fcolor-diagnostics -ftemplate-depth=1024 -Wno-unused-command-line-argument")
|
||||
elseif(${CMAKE_CXX_COMPILER_ID} STREQUAL "GNU")
|
||||
elseif(CMAKE_CXX_COMPILER_ID MATCHES "GNU")
|
||||
set(COLOR_FLAG "-fdiagnostics-color=auto")
|
||||
check_cxx_compiler_flag("-fdiagnostics-color=auto" HAS_COLOR_FLAG)
|
||||
if(NOT HAS_COLOR_FLAG)
|
||||
@@ -337,13 +337,14 @@ elseif(${CMAKE_CXX_COMPILER_ID} STREQUAL "GNU")
|
||||
set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -fpermissive")
|
||||
endif()
|
||||
|
||||
elseif(${CMAKE_CXX_COMPILER_ID} STREQUAL "Intel")
|
||||
elseif(CMAKE_CXX_COMPILER_ID MATCHES "Intel")
|
||||
# using Intel C++
|
||||
set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -static-intel -wd10237 -Wall -ipo -fPIC")
|
||||
elseif(${CMAKE_CXX_COMPILER_ID} STREQUAL "MSVC")
|
||||
elseif(CMAKE_CXX_COMPILER_ID MATCHES "MSVC")
|
||||
# using Visual Studio C++
|
||||
set(BOOST_COMPONENTS ${BOOST_COMPONENTS} zlib)
|
||||
set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} /bigobj") # avoid compiler error C1128 from scripting_environment_lua.cpp
|
||||
set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} /DWIN32_LEAN_AND_MEAN") # avoid compiler error C2011 from dual #include of winsock.h and winsock2.h
|
||||
add_dependency_defines(-DBOOST_LIB_DIAGNOSTIC)
|
||||
add_dependency_defines(-D_CRT_SECURE_NO_WARNINGS)
|
||||
add_dependency_defines(-DNOMINMAX) # avoid min and max macros that can break compilation
|
||||
@@ -359,7 +360,7 @@ execute_process(COMMAND ${CMAKE_CXX_COMPILER} "-Wl,--version" ERROR_QUIET OUTPUT
|
||||
# For ld.gold and ld.bfs (the GNU linkers) we optimize hard
|
||||
if("${LINKER_VERSION}" MATCHES "GNU gold" OR "${LINKER_VERSION}" MATCHES "GNU ld")
|
||||
message(STATUS "Setting linker optimizations")
|
||||
if(NOT (${CMAKE_CXX_COMPILER_ID} STREQUAL "MSVC" OR "${LD_AVOID_GC_SECTIONS}"))
|
||||
if(NOT (CMAKE_CXX_COMPILER_ID MATCHES "MSVC" OR "${LD_AVOID_GC_SECTIONS}"))
|
||||
# Tell compiler to put every function in separate section, linker can then match sections and functions
|
||||
set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -ffunction-sections -fdata-sections")
|
||||
# Tell linker to do dead code and data eminination during link time discarding sections
|
||||
@@ -377,7 +378,7 @@ set(CMAKE_SHARED_LINKER_FLAGS "${CMAKE_SHARED_LINKER_FLAGS} ${LINKER_FLAGS}")
|
||||
set(CMAKE_MODULE_LINKER_FLAGS "${CMAKE_MODULE_LINKER_FLAGS} ${LINKER_FLAGS}")
|
||||
|
||||
# Activate C++1y
|
||||
if(NOT ${CMAKE_CXX_COMPILER_ID} STREQUAL "MSVC")
|
||||
if(NOT CMAKE_CXX_COMPILER_ID MATCHES "MSVC")
|
||||
set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -std=c++1y")
|
||||
set(OSRM_CXXFLAGS "${OSRM_CXXFLAGS} -std=c++1y")
|
||||
endif()
|
||||
@@ -568,7 +569,7 @@ else()
|
||||
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"))
|
||||
if(ENABLE_CCACHE AND (CMAKE_CXX_COMPILER_ID MATCHES "Clang" OR CMAKE_CXX_COMPILER_ID MATCHES "GNU"))
|
||||
find_program(CCACHE_FOUND ccache)
|
||||
if(CCACHE_FOUND)
|
||||
message(STATUS "Using ccache to speed up incremental builds")
|
||||
|
||||
+1
-1
@@ -18,7 +18,7 @@ if [ x"$remote" = xorigin ] ; then
|
||||
echo "Rejected push to $remote/master" ; exit 1
|
||||
fi
|
||||
|
||||
./scripts/format.sh
|
||||
./scripts/format.sh && ./scripts/error_on_dirty.sh
|
||||
if [ $? -ne 0 ] ; then
|
||||
echo "Unstaged format changes" ; exit 1
|
||||
fi
|
||||
|
||||
+30
-29
@@ -27,11 +27,11 @@ var osrm = new OSRM('network.osrm');
|
||||
This requires you to run `osrm-datastore` prior to creating an `OSRM` object.
|
||||
- `options.path` **[String](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/String)?** The path to the `.osrm` files. This is mutually exclusive with setting {options.shared_memory} to true.
|
||||
- `options.max_locations_trip` **[Number](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Number)?** Max. locations supported in trip query (default: unlimited).
|
||||
- `options.max_locations_viaroute` **[Number](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Number)?** Max. locations supported in viaroute query 9default: unlimited).
|
||||
- `options.max_locations_viaroute` **[Number](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Number)?** Max. locations supported in viaroute query (default: unlimited).
|
||||
- `options.max_locations_distance_table` **[Number](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Number)?** Max. locations supported in distance table query (default: unlimited).
|
||||
- `options.max_locations_map_matching` **[Number](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Number)?** Max. locations supported in map matching query (default: unlimited).
|
||||
- `options.max_locations_map_matching` **[Number](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Number)?** Max. locations supported in map-matching query (default: unlimited).
|
||||
- `options.max_results_nearest` **[Number](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Number)?** Max. results supported in nearest query (default: unlimited).
|
||||
- `options.max_alternatives` **[Number](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Number)?** Max. number of alternative routes supported (default: 3).
|
||||
- `options.max_alternatives` **[Number](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Number)?** Max.number of alternatives supported in alternative routes query (default: 3).
|
||||
|
||||
### route
|
||||
|
||||
@@ -45,15 +45,16 @@ Returns the fastest route between two or more coordinates while visiting the way
|
||||
Can be `null` or an array of `[{value},{range}]` with `integer 0 .. 360,integer 0 .. 180`.
|
||||
- `options.radiuses` **[Array](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Array)?** Limits the coordinate snapping to streets in the given radius in meters. Can be `null` (unlimited, default) or `double >= 0`.
|
||||
- `options.hints` **[Array](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Array)?** Hints for the coordinate snapping. Array of base64 encoded strings.
|
||||
- `options.alternatives` **[Boolean](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Boolean)** Search for alternative routes and return as well.
|
||||
_Please note that even if an alternative route is requested, a result cannot be guaranteed._ (optional, default `false`)
|
||||
- `options.steps` **[Boolean](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Boolean)** Returned route steps for each route leg. (optional, default `false`)
|
||||
- `options.alternatives` **[Boolean](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Boolean)** Search for alternative routes. (optional, default `false`)
|
||||
- `options.alternatives` **[Number](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Number)** Search for up to this many alternative routes.
|
||||
_Please note that even if alternative routes are requested, a result cannot be guaranteed._ (optional, default `0`)
|
||||
- `options.steps` **[Boolean](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Boolean)** Return route steps for each route leg. (optional, default `false`)
|
||||
- `options.annotations` **([Array](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Array) \| [Boolean](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Boolean))** An array with strings of `duration`, `nodes`, `distance`, `weight`, `datasources`, `speed` or boolean for enabling/disabling all. (optional, default `false`)
|
||||
- `options.geometries` **[String](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/String)** Returned route geometry format (influences overview and per step). Can also be `geojson`. (optional, default `polyline`)
|
||||
- `options.overview` **[String](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/String)** Add overview geometry either `full`, `simplified` according to highest zoom level it could be display on, or not at all (`false`). (optional, default `simplified`)
|
||||
- `options.continue_straight` **[Boolean](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Boolean)?** 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.
|
||||
`null`/`true`/`false`
|
||||
- `options.approaches` **[Array](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Array)?** Keep waypoints on curb side. Can be `null` (unrestricted, default) or `curb`.
|
||||
`null`/`true`/`false`
|
||||
- `callback` **[Function](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Statements/function)**
|
||||
|
||||
**Examples**
|
||||
@@ -194,14 +195,14 @@ if they can not be matched successfully.
|
||||
- `options.bearings` **[Array](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Array)?** Limits the search to segments with given bearing in degrees towards true north in clockwise direction.
|
||||
Can be `null` or an array of `[{value},{range}]` with `integer 0 .. 360,integer 0 .. 180`.
|
||||
- `options.hints` **[Array](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Array)?** Hints for the coordinate snapping. Array of base64 encoded strings.
|
||||
- `options.steps` **[Boolean](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Boolean)** Returned route steps for each route. (optional, default `false`)
|
||||
- `options.steps` **[Boolean](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Boolean)** Return route steps for each route. (optional, default `false`)
|
||||
- `options.annotations` **([Array](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Array) \| [Boolean](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Boolean))** An array with strings of `duration`, `nodes`, `distance`, `weight`, `datasources`, `speed` or boolean for enabling/disabling all. (optional, default `false`)
|
||||
- `options.geometries` **[String](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/String)** Returned route geometry format (influences overview and per step). Can also be `geojson`. (optional, default `polyline`)
|
||||
- `options.overview` **[String](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/String)** Add overview geometry either `full`, `simplified` according to highest zoom level it could be display on, or not at all (`false`). (optional, default `simplified`)
|
||||
- `options.timestamps` **[Array](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Array)<[Number](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Number)>?** Timestamp of the input location (integers, UNIX-like timestamp).
|
||||
- `options.radiuses` **[Array](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Array)?** Standard deviation of GPS precision used for map matching. If applicable use GPS accuracy. Can be `null` for default value `5` meters or `double >= 0`.
|
||||
- `options.gaps` **[String](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/String)** Allows the input track splitting based on huge timestamp gaps between points. Either `split` or `ignore`. (optional, default `split`)
|
||||
- `options.tidy` **[Boolean](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Boolean)** Allows the input track modification to obtain better matching quality for noisy tracks. (optional, default `false`)
|
||||
- `options.gaps` **[String](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/String)?** Allows the input track splitting based on huge timestamp gaps between points. Either `split` or `ignore` (optional, default `split`).
|
||||
- `options.tidy` **[Boolean](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Boolean)?** Allows the input track modification to obtain better matching quality for noisy tracks (optional, default `false`).
|
||||
- `callback` **[Function](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Statements/function)**
|
||||
|
||||
**Examples**
|
||||
@@ -235,25 +236,7 @@ The trip plugin solves the Traveling Salesman Problem using a greedy heuristic
|
||||
waypoints. The returned path does not have to be the shortest path, _ as TSP is NP-hard it is
|
||||
only an approximation.
|
||||
|
||||
**Parameters**
|
||||
|
||||
- `options` **[Object](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Object)** Object literal containing parameters for the trip query.
|
||||
- `options.coordinates` **[Array](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Array)?** The coordinates this request will use, coordinates as `[{lon},{lat}]` values, in decimal degrees.
|
||||
- `options.bearings` **[Array](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Array)?** Limits the search to segments with given bearing in degrees towards true north in clockwise direction.
|
||||
Can be `null` or an array of `[{value},{range}]` with `integer 0 .. 360,integer 0 .. 180`.
|
||||
- `options.radiuses` **[Array](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Array)?** Limits the coordinate snapping to streets in the given radius in meters. Can be `double >= 0` or `null` (unlimited, default).
|
||||
- `options.hints` **[Array](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Array)?** Hints for the coordinate snapping. Array of base64 encoded strings.
|
||||
- `options.steps` **[Boolean](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Boolean)** Returned route steps for each route. (optional, default `false`)
|
||||
- `options.annotations` **([Array](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Array) \| [Boolean](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Boolean))** An array with strings of `duration`, `nodes`, `distance`, `weight`, `datasources`, `speed` or boolean for enabling/disabling all. (optional, default `false`)
|
||||
- `options.geometries` **[String](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/String)** Returned route geometry format (influences overview and per step). Can also be `geojson`. (optional, default `polyline`)
|
||||
- `options.overview` **[String](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/String)** Add overview geometry either `full`, `simplified` (optional, default `simplified`)
|
||||
- `options.roundtrip` **[Boolean](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Boolean)** Returned route is a roundtrip (route returns to first location). (optional, default `true`)
|
||||
- `options.source` **[String](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/String)** Returned route starts at `any` or `first` coordinate. (optional, default `any`)
|
||||
- `options.destination` **[String](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/String)** Returned route ends at `any` or `last` coordinate. (optional, default `any`)
|
||||
- `options.approaches` **[Array](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Array)?** Keep waypoints on curb side. Can be `null` (unrestricted, default) or `curb`.
|
||||
- `callback` **[Function](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Statements/function)**
|
||||
|
||||
A requirement for computing trips is that all input coordinates are connected.
|
||||
Note that all input coordinates have to be connected for the trip service to work.
|
||||
Currently, not all combinations of `roundtrip`, `source` and `destination` are supported.
|
||||
Right now, the following combinations are possible:
|
||||
|
||||
@@ -268,6 +251,24 @@ Right now, the following combinations are possible:
|
||||
| false | any | last | no |
|
||||
| false | any | any | no |
|
||||
|
||||
**Parameters**
|
||||
|
||||
- `options` **[Object](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Object)** Object literal containing parameters for the trip query.
|
||||
- `options.coordinates` **[Array](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Array)?** The coordinates this request will use, coordinates as `[{lon},{lat}]` values, in decimal degrees.
|
||||
- `options.bearings` **[Array](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Array)?** Limits the search to segments with given bearing in degrees towards true north in clockwise direction.
|
||||
Can be `null` or an array of `[{value},{range}]` with `integer 0 .. 360,integer 0 .. 180`.
|
||||
- `options.radiuses` **[Array](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Array)?** Limits the coordinate snapping to streets in the given radius in meters. Can be `double >= 0` or `null` (unlimited, default).
|
||||
- `options.hints` **[Array](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Array)?** Hints for the coordinate snapping. Array of base64 encoded strings.
|
||||
- `options.steps` **[Boolean](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Boolean)** Return route steps for each route. (optional, default `false`)
|
||||
- `options.annotations` **([Array](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Array) \| [Boolean](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Boolean))** An array with strings of `duration`, `nodes`, `distance`, `weight`, `datasources`, `speed` or boolean for enabling/disabling all. (optional, default `false`)
|
||||
- `options.geometries` **[String](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/String)** Returned route geometry format (influences overview and per step). Can also be `geojson`. (optional, default `polyline`)
|
||||
- `options.overview` **[String](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/String)** Add overview geometry either `full`, `simplified` (optional, default `simplified`)
|
||||
- `options.roundtrip` **[Boolean](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Boolean)** Return route is a roundtrip. (optional, default `true`)
|
||||
- `options.source` **[String](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/String)** Return route starts at `any` or `first` coordinate. (optional, default `any`)
|
||||
- `options.destination` **[String](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/String)** Return route ends at `any` or `last` coordinate. (optional, default `any`)
|
||||
- `options.approaches` **[Array](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Array)?** Keep waypoints on curb side. Can be `null` (unrestricted, default) or `curb`.
|
||||
- `callback` **[Function](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Statements/function)**
|
||||
|
||||
**Examples**
|
||||
|
||||
```javascript
|
||||
|
||||
+2
-2
@@ -47,10 +47,10 @@ We may introduce forward-compatible changes: query parameters and response prope
|
||||
4. Make sure the `package.json` is up to date.
|
||||
5. Make sure all tests are passing (e.g. Travis CI gives you a :thumbs_up:)
|
||||
6. Use an annotated tag to mark the release: `git tag vx.y.z -a` Body of the tag description should be the changelog entries.
|
||||
7. 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
|
||||
7. Use `npm run 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
|
||||
8. Push tags and commits: `git push; git push --tags`
|
||||
9. If not a release-candidate: Write a mailing-list post to osrm-talk@openstreetmap.org to announce the release
|
||||
10. Wait until the travis build has been completed and check if the node binaries were published by doing:
|
||||
`rm -rf node_modules && npm install` locally.
|
||||
11. For final releases run `npm publish` or `npm publish --tag next` for release candidates.
|
||||
|
||||
12. Bump version in `package.json` to `{MAJOR}.{MINOR+1}.0-latest.1` on the `master` branch after the release.
|
||||
|
||||
@@ -21,13 +21,6 @@ Feature: Bicycle - Handle cycling
|
||||
When I route I should get
|
||||
| from | to | route | modes |
|
||||
| a | g | abc,cde,efg,efg | cycling,cycling,cycling,cycling |
|
||||
| b | f | abc,cde,efg,efg | cycling,cycling,cycling,cycling |
|
||||
| e | c | cde,cde | cycling,cycling |
|
||||
| e | b | cde,abc,abc | cycling,cycling,cycling |
|
||||
| e | a | cde,abc,abc | cycling,cycling,cycling |
|
||||
| c | e | cde,cde | cycling,cycling |
|
||||
| c | f | cde,efg,efg | cycling,cycling,cycling |
|
||||
| c | g | cde,efg,efg | cycling,cycling,cycling |
|
||||
|
||||
Scenario: Bicycle - Properly handle durations
|
||||
Given the node map
|
||||
|
||||
@@ -21,15 +21,15 @@ Feature: Bike - Destination only, no passing through
|
||||
| axye | |
|
||||
|
||||
When I route I should get
|
||||
| from | to | route |
|
||||
| a | b | ab,ab |
|
||||
| a | c | ab,bcd,bcd |
|
||||
| a | d | ab,bcd,bcd |
|
||||
| a | e | axye,axye |
|
||||
| e | d | de,de |
|
||||
| e | c | de,bcd,bcd |
|
||||
| e | b | de,bcd,bcd |
|
||||
| e | a | axye,axye |
|
||||
| from | to | route |
|
||||
| a | b | ab,ab |
|
||||
| a | c | ab,bcd |
|
||||
| a | d | ab,bcd |
|
||||
| a | e | axye,axye |
|
||||
| e | d | de,de |
|
||||
| e | c | de,bcd |
|
||||
| e | b | de,bcd |
|
||||
| e | a | axye,axye |
|
||||
|
||||
Scenario: Bike - Destination only street
|
||||
Given the node map
|
||||
@@ -49,15 +49,15 @@ Feature: Bike - Destination only, no passing through
|
||||
| axye | |
|
||||
|
||||
When I route I should get
|
||||
| from | to | route |
|
||||
| a | b | ab,ab |
|
||||
| a | c | ab,bc,bc |
|
||||
| a | d | ab,bc,cd,cd |
|
||||
| a | e | axye,axye |
|
||||
| e | d | de,de |
|
||||
| e | c | de,cd,cd |
|
||||
| e | b | de,cd,bc,bc |
|
||||
| e | a | axye,axye |
|
||||
| from | to | route |
|
||||
| a | b | ab,ab |
|
||||
| a | c | ab,bc |
|
||||
| a | d | ab,bc,cd |
|
||||
| a | e | axye,axye |
|
||||
| e | d | de,de |
|
||||
| e | c | de,cd,cd |
|
||||
| e | b | de,cd,bc |
|
||||
| e | a | axye,axye |
|
||||
|
||||
Scenario: Bike - Routing inside a destination only area
|
||||
Given the node map
|
||||
@@ -76,8 +76,8 @@ Feature: Bike - Destination only, no passing through
|
||||
| axye | |
|
||||
|
||||
When I route I should get
|
||||
| from | to | route |
|
||||
| a | e | ab,bc,cd,de,de |
|
||||
| e | a | de,cd,bc,ab,ab |
|
||||
| b | d | bc,cd,cd |
|
||||
| d | b | cd,bc,bc |
|
||||
| from | to | route |
|
||||
| a | e | ab,bc,cd,de |
|
||||
| e | a | de,cd,bc,ab |
|
||||
| b | d | bc,cd |
|
||||
| d | b | cd,bc |
|
||||
|
||||
@@ -21,12 +21,7 @@ Feature: Bike - Handle ferry routes
|
||||
When I route I should get
|
||||
| from | to | route |
|
||||
| a | g | abc,cde,efg,efg |
|
||||
| b | f | abc,cde,efg,efg |
|
||||
| e | c | cde,cde |
|
||||
| e | b | cde,abc,abc |
|
||||
| e | a | cde,abc,abc |
|
||||
| c | e | cde,cde |
|
||||
| c | f | cde,efg,efg |
|
||||
| c | g | cde,efg,efg |
|
||||
|
||||
Scenario: Bike - Ferry duration, single node
|
||||
|
||||
@@ -20,11 +20,8 @@ Feature: Bike - Mode flag
|
||||
When I route I should get
|
||||
| from | to | route | modes |
|
||||
| a | d | ab,bc,cd,cd | cycling,ferry,cycling,cycling |
|
||||
| d | a | cd,bc,ab,ab | cycling,ferry,cycling,cycling |
|
||||
| c | a | bc,ab,ab | ferry,cycling,cycling |
|
||||
| d | b | cd,bc,bc | cycling,ferry,ferry |
|
||||
| a | c | ab,bc,bc | cycling,ferry,ferry |
|
||||
| b | d | bc,cd,cd | ferry,cycling,cycling |
|
||||
|
||||
Scenario: Bike - Mode when using a train
|
||||
Given the node map
|
||||
@@ -42,12 +39,10 @@ Feature: Bike - Mode flag
|
||||
When I route I should get
|
||||
| from | to | route | modes |
|
||||
| a | d | ab,bc,cd,cd | cycling,train,cycling,cycling |
|
||||
| d | a | cd,bc,ab,ab | cycling,train,cycling,cycling |
|
||||
| c | a | bc,ab,ab | train,cycling,cycling |
|
||||
| d | b | cd,bc,bc | cycling,train,train |
|
||||
| a | c | ab,bc,bc | cycling,train,train |
|
||||
| b | d | bc,cd,cd | train,cycling,cycling |
|
||||
|
||||
#representative test for all pushes (and mode changes). Where a bike is pushed is tested over in access.feature
|
||||
Scenario: Bike - Mode when pushing bike against oneways
|
||||
Given the node map
|
||||
"""
|
||||
@@ -70,96 +65,6 @@ Feature: Bike - Mode flag
|
||||
| d | a | cd,bc,ab,ab | cycling,pushing bike,cycling,cycling |
|
||||
| c | a | bc,ab,ab | pushing bike,cycling,cycling |
|
||||
| d | b | cd,bc,bc | cycling,pushing bike,pushing bike |
|
||||
| a | c | ab,bc,bc | cycling,cycling,cycling |
|
||||
| b | d | bc,cd,cd | cycling,cycling,cycling |
|
||||
|
||||
Scenario: Bike - Mode when pushing on pedestrain streets
|
||||
Given the node map
|
||||
"""
|
||||
a b
|
||||
c d
|
||||
"""
|
||||
|
||||
And the ways
|
||||
| nodes | highway |
|
||||
| ab | primary |
|
||||
| bc | pedestrian |
|
||||
| cd | primary |
|
||||
|
||||
When I route I should get
|
||||
| from | to | route | modes |
|
||||
| a | d | ab,bc,cd,cd | cycling,pushing bike,cycling,cycling |
|
||||
| d | a | cd,bc,ab,ab | cycling,pushing bike,cycling,cycling |
|
||||
| c | a | bc,ab,ab | pushing bike,cycling,cycling |
|
||||
| d | b | cd,bc,bc | cycling,pushing bike,pushing bike |
|
||||
| a | c | ab,bc,bc | cycling,pushing bike,pushing bike |
|
||||
| b | d | bc,cd,cd | pushing bike,cycling,cycling |
|
||||
|
||||
Scenario: Bike - Mode when pushing on pedestrain areas
|
||||
Given the node map
|
||||
"""
|
||||
a b
|
||||
c d f
|
||||
"""
|
||||
|
||||
And the ways
|
||||
| nodes | highway | area |
|
||||
| ab | primary | |
|
||||
| bcd | pedestrian | yes |
|
||||
| df | primary | |
|
||||
|
||||
When I route I should get
|
||||
| from | to | route | modes |
|
||||
| a | f | ab,bcd,df,df | cycling,pushing bike,cycling,cycling |
|
||||
| f | a | df,bcd,ab,ab | cycling,pushing bike,cycling,cycling |
|
||||
| d | a | bcd,ab,ab | pushing bike,cycling,cycling |
|
||||
| f | b | df,bcd,bcd | cycling,pushing bike,pushing bike |
|
||||
| a | d | ab,bcd,bcd | cycling,pushing bike,pushing bike |
|
||||
| b | f | bcd,df,df | pushing bike,cycling,cycling |
|
||||
|
||||
Scenario: Bike - Mode when pushing on steps
|
||||
Given the node map
|
||||
"""
|
||||
a b
|
||||
c d f
|
||||
"""
|
||||
|
||||
And the ways
|
||||
| nodes | highway |
|
||||
| ab | primary |
|
||||
| bc | steps |
|
||||
| cd | primary |
|
||||
|
||||
When I route I should get
|
||||
| from | to | route | modes |
|
||||
| a | d | ab,bc,cd,cd | cycling,pushing bike,cycling,cycling |
|
||||
| d | a | cd,bc,ab,ab | cycling,pushing bike,cycling,cycling |
|
||||
| c | a | bc,ab,ab | pushing bike,cycling,cycling |
|
||||
| d | b | cd,bc,bc | cycling,pushing bike,pushing bike |
|
||||
| a | c | ab,bc,bc | cycling,pushing bike,pushing bike |
|
||||
| b | d | bc,cd,cd | pushing bike,cycling,cycling |
|
||||
|
||||
Scenario: Bike - Mode when bicycle=dismount
|
||||
Given the node map
|
||||
"""
|
||||
a b
|
||||
c d f
|
||||
"""
|
||||
|
||||
And the ways
|
||||
| nodes | highway | bicycle |
|
||||
| ab | primary | |
|
||||
| bc | primary | dismount |
|
||||
| cd | primary | |
|
||||
|
||||
When I route I should get
|
||||
| from | to | route | modes |
|
||||
| a | d | ab,bc,cd,cd | cycling,pushing bike,cycling,cycling |
|
||||
| d | a | cd,bc,ab,ab | cycling,pushing bike,cycling,cycling |
|
||||
| c | a | bc,ab,ab | pushing bike,cycling,cycling |
|
||||
| d | b | cd,bc,bc | cycling,pushing bike,pushing bike |
|
||||
| a | c | ab,bc,bc | cycling,pushing bike,pushing bike |
|
||||
| b | d | bc,cd,cd | pushing bike,cycling,cycling |
|
||||
|
||||
Scenario: Bicycle - Modes when starting on forward oneway
|
||||
Given the node map
|
||||
|
||||
@@ -1,47 +0,0 @@
|
||||
@routing @bicycle @ref @name
|
||||
Feature: Bike - Way ref
|
||||
|
||||
Background:
|
||||
Given the profile "bicycle"
|
||||
|
||||
Scenario: Bike - Way with both name and ref
|
||||
Given the node map
|
||||
"""
|
||||
a b
|
||||
"""
|
||||
|
||||
And the ways
|
||||
| nodes | name | ref |
|
||||
| ab | Utopia Drive | E7 |
|
||||
|
||||
When I route I should get
|
||||
| from | to | route | ref |
|
||||
| a | b | Utopia Drive,Utopia Drive | E7,E7 |
|
||||
|
||||
Scenario: Bike - Way with only ref
|
||||
Given the node map
|
||||
"""
|
||||
a b
|
||||
"""
|
||||
|
||||
And the ways
|
||||
| nodes | name | ref |
|
||||
| ab | | E7 |
|
||||
|
||||
When I route I should get
|
||||
| from | to | route | ref |
|
||||
| a | b | , | E7,E7 |
|
||||
|
||||
Scenario: Bike - Way with only name
|
||||
Given the node map
|
||||
"""
|
||||
a b
|
||||
"""
|
||||
|
||||
And the ways
|
||||
| nodes | name |
|
||||
| ab | Utopia Drive |
|
||||
|
||||
When I route I should get
|
||||
| from | to | route |
|
||||
| a | b | Utopia Drive,Utopia Drive |
|
||||
@@ -7,6 +7,8 @@ Feature: Bike - Turn restrictions
|
||||
Given the profile "bicycle"
|
||||
Given a grid size of 200 meters
|
||||
|
||||
# check to see if bicycle profiles handle relations. The code path is the same as in cars.
|
||||
# If relations are passed, all variants tested in car also work for bike
|
||||
@no_turning
|
||||
Scenario: Bike - No left turn
|
||||
Given the node map
|
||||
@@ -33,188 +35,7 @@ Feature: Bike - Turn restrictions
|
||||
| s | n | sj,nj,nj |
|
||||
| s | e | sj,ej,ej |
|
||||
|
||||
@no_turning
|
||||
Scenario: Bike - No right turn
|
||||
Given the node map
|
||||
"""
|
||||
n
|
||||
w j e
|
||||
s
|
||||
"""
|
||||
|
||||
And the ways
|
||||
| nodes | oneway | foot |
|
||||
| sj | yes | no |
|
||||
| nj | -1 | no |
|
||||
| wj | -1 | no |
|
||||
| ej | -1 | no |
|
||||
|
||||
And the relations
|
||||
| type | way:from | way:to | node:via | restriction |
|
||||
| restriction | sj | ej | j | no_right_turn |
|
||||
|
||||
When I route I should get
|
||||
| from | to | route |
|
||||
| s | w | sj,wj,wj |
|
||||
| s | n | sj,nj,nj |
|
||||
| s | e | sj,ej,ej |
|
||||
|
||||
@no_turning
|
||||
Scenario: Bike - No u-turn
|
||||
Given the node map
|
||||
"""
|
||||
n
|
||||
w j e
|
||||
s
|
||||
"""
|
||||
|
||||
And the ways
|
||||
| nodes | oneway | foot |
|
||||
| sj | yes | no |
|
||||
| nj | -1 | no |
|
||||
| wj | -1 | no |
|
||||
| ej | -1 | no |
|
||||
|
||||
And the relations
|
||||
| type | way:from | way:to | node:via | restriction |
|
||||
| restriction | sj | wj | j | no_u_turn |
|
||||
|
||||
When I route I should get
|
||||
| from | to | route |
|
||||
| s | w | sj,wj,wj |
|
||||
| s | n | sj,nj,nj |
|
||||
| s | e | sj,ej,ej |
|
||||
|
||||
@no_turning
|
||||
Scenario: Bike - Handle any no_* relation
|
||||
Given the node map
|
||||
"""
|
||||
n
|
||||
w j e
|
||||
s
|
||||
"""
|
||||
|
||||
And the ways
|
||||
| nodes | oneway | foot |
|
||||
| sj | yes | no |
|
||||
| nj | -1 | no |
|
||||
| wj | -1 | no |
|
||||
| ej | -1 | no |
|
||||
|
||||
And the relations
|
||||
| type | way:from | way:to | node:via | restriction |
|
||||
| restriction | sj | wj | j | no_weird_zigzags |
|
||||
|
||||
When I route I should get
|
||||
| from | to | route |
|
||||
| s | w | sj,wj,wj |
|
||||
| s | n | sj,nj,nj |
|
||||
| s | e | sj,ej,ej |
|
||||
|
||||
@only_turning
|
||||
Scenario: Bike - Only left turn
|
||||
Given the node map
|
||||
"""
|
||||
n
|
||||
w j e
|
||||
s
|
||||
"""
|
||||
|
||||
And the ways
|
||||
| nodes | oneway | foot |
|
||||
| sj | yes | no |
|
||||
| nj | -1 | no |
|
||||
| wj | -1 | no |
|
||||
| ej | -1 | no |
|
||||
|
||||
And the relations
|
||||
| type | way:from | way:to | node:via | restriction |
|
||||
| restriction | sj | wj | j | only_left_turn |
|
||||
|
||||
When I route I should get
|
||||
| from | to | route |
|
||||
| s | w | sj,wj,wj |
|
||||
| s | n | sj,nj,nj |
|
||||
| s | e | sj,ej,ej |
|
||||
|
||||
@only_turning
|
||||
Scenario: Bike - Only right turn
|
||||
Given the node map
|
||||
"""
|
||||
n
|
||||
w j e
|
||||
s
|
||||
"""
|
||||
|
||||
And the ways
|
||||
| nodes | oneway | foot |
|
||||
| sj | yes | no |
|
||||
| nj | -1 | no |
|
||||
| wj | -1 | no |
|
||||
| ej | -1 | no |
|
||||
|
||||
And the relations
|
||||
| type | way:from | way:to | node:via | restriction |
|
||||
| restriction | sj | ej | j | only_right_turn |
|
||||
|
||||
When I route I should get
|
||||
| from | to | route |
|
||||
| s | w | sj,wj,wj |
|
||||
| s | n | sj,nj,nj |
|
||||
| s | e | sj,ej,ej |
|
||||
|
||||
@only_turning
|
||||
Scenario: Bike - Only straight on
|
||||
Given the node map
|
||||
"""
|
||||
n
|
||||
w j e
|
||||
s
|
||||
"""
|
||||
|
||||
And the ways
|
||||
| nodes | oneway | foot |
|
||||
| sj | yes | no |
|
||||
| nj | -1 | no |
|
||||
| wj | -1 | no |
|
||||
| ej | -1 | no |
|
||||
|
||||
And the relations
|
||||
| type | way:from | way:to | node:via | restriction |
|
||||
| restriction | sj | nj | j | only_straight_on |
|
||||
|
||||
When I route I should get
|
||||
| from | to | route |
|
||||
| s | w | sj,wj,wj |
|
||||
| s | n | sj,nj,nj |
|
||||
| s | e | sj,ej,ej |
|
||||
|
||||
@no_turning
|
||||
Scenario: Bike - Handle any only_* restriction
|
||||
Given the node map
|
||||
"""
|
||||
n
|
||||
w j e
|
||||
s
|
||||
"""
|
||||
|
||||
And the ways
|
||||
| nodes | oneway | foot |
|
||||
| sj | yes | no |
|
||||
| nj | -1 | no |
|
||||
| wj | -1 | no |
|
||||
| ej | -1 | no |
|
||||
|
||||
And the relations
|
||||
| type | way:from | way:to | node:via | restriction |
|
||||
| restriction | sj | nj | j | only_weird_zigzags |
|
||||
|
||||
When I route I should get
|
||||
| from | to | route |
|
||||
| s | w | sj,wj,wj |
|
||||
| s | n | sj,nj,nj |
|
||||
| s | e | sj,ej,ej |
|
||||
|
||||
## exceptions are different for bike over car and need to be tested here
|
||||
@except
|
||||
Scenario: Bike - Except tag and on no_ restrictions
|
||||
Given the node map
|
||||
|
||||
@@ -22,13 +22,7 @@ Feature: Car - Handle driving
|
||||
When I route I should get
|
||||
| from | to | route | modes |
|
||||
| a | g | abc,cde,efg,efg | driving,driving,driving,driving |
|
||||
| b | f | abc,cde,efg,efg | driving,driving,driving,driving |
|
||||
| e | c | cde,cde | driving,driving |
|
||||
| e | b | cde,abc,abc | driving,driving,driving |
|
||||
| e | a | cde,abc,abc | driving,driving,driving |
|
||||
| c | e | cde,cde | driving,driving |
|
||||
| c | f | cde,efg,efg | driving,driving,driving |
|
||||
| c | g | cde,efg,efg | driving,driving,driving |
|
||||
|
||||
Scenario: Car - Control test without durations, osrm uses movable bridge speed to calculate duration
|
||||
Given the node map
|
||||
@@ -47,8 +41,6 @@ Feature: Car - Handle driving
|
||||
When I route I should get
|
||||
| from | to | route | modes | speed | time |
|
||||
| a | g | abc,cde,efg,efg | driving,driving,driving,driving | 13 km/h | 340s +-1 |
|
||||
| b | f | abc,cde,efg,efg | driving,driving,driving,driving | 9 km/h | 318s +-1 |
|
||||
| c | e | cde,cde | driving,driving | 5 km/h | 295s +-1 |
|
||||
| e | c | cde,cde | driving,driving | 5 km/h | 295s +-1 |
|
||||
|
||||
Scenario: Car - Properly handle durations
|
||||
@@ -68,6 +60,5 @@ Feature: Car - Handle driving
|
||||
When I route I should get
|
||||
| from | to | route | modes | speed |
|
||||
| a | g | abc,cde,efg,efg | driving,driving,driving,driving | 7 km/h |
|
||||
| b | f | abc,cde,efg,efg | driving,driving,driving,driving | 5 km/h |
|
||||
| c | e | cde,cde | driving,driving | 2 km/h |
|
||||
| e | c | cde,cde | driving,driving | 2 km/h |
|
||||
|
||||
@@ -72,6 +72,75 @@ Feature: Car - Turn restrictions
|
||||
| n | m | nj,pjm,pjm |
|
||||
| s | m | js,pjm,pjm |
|
||||
|
||||
@no_turning @conditionals
|
||||
Scenario: Car - Restriction With Compressed Geometry
|
||||
Given the extract extra arguments "--parse-conditional-restrictions"
|
||||
# time stamp for 10am on Tues, 02 May 2017 GMT
|
||||
Given the contract extra arguments "--time-zone-file=test/data/tz/{timezone_names}/guinea.geojson --parse-conditionals-from-now=1493719200"
|
||||
Given the customize extra arguments "--time-zone-file=test/data/tz/{timezone_names}/guinea.geojson --parse-conditionals-from-now=1493719200"
|
||||
|
||||
Given the node map
|
||||
"""
|
||||
n
|
||||
|
|
||||
i
|
||||
|
|
||||
j-k-l-m
|
||||
|
|
||||
s
|
||||
"""
|
||||
|
||||
And the ways
|
||||
| nodes |
|
||||
| nij |
|
||||
| js |
|
||||
| jklm |
|
||||
|
||||
And the relations
|
||||
| type | way:from | way:to | node:via | restriction:conditional |
|
||||
| restriction | nij | jklm | j | no_left_turn @ (Mo-Fr 07:00-10:30) |
|
||||
|
||||
When I route I should get
|
||||
| from | to | route |
|
||||
| n | m | nij,js,js,jklm,jklm |
|
||||
|
||||
@no_turning @conditionals
|
||||
Scenario: Car - Restriction With Compressed Geometry and Traffic Signal
|
||||
Given the extract extra arguments "--parse-conditional-restrictions"
|
||||
# time stamp for 10am on Tues, 02 May 2017 GMT
|
||||
Given the contract extra arguments "--time-zone-file=test/data/tz/{timezone_names}/guinea.geojson --parse-conditionals-from-now=1493719200"
|
||||
Given the customize extra arguments "--time-zone-file=test/data/tz/{timezone_names}/guinea.geojson --parse-conditionals-from-now=1493719200"
|
||||
|
||||
Given the node map
|
||||
"""
|
||||
n
|
||||
|
|
||||
i
|
||||
|
|
||||
j-k-l-m
|
||||
|
|
||||
s
|
||||
"""
|
||||
|
||||
And the ways
|
||||
| nodes |
|
||||
| nij |
|
||||
| js |
|
||||
| jklm |
|
||||
|
||||
And the nodes
|
||||
| node | highway |
|
||||
| i | traffic_signal |
|
||||
| k | traffic_signal |
|
||||
|
||||
And the relations
|
||||
| type | way:from | way:to | node:via | restriction:conditional |
|
||||
| restriction | nij | jklm | j | no_left_turn @ (Mo-Fr 07:00-10:30) |
|
||||
|
||||
When I route I should get
|
||||
| from | to | route |
|
||||
| n | m | nij,js,js,jklm,jklm |
|
||||
|
||||
@no_turning @conditionals
|
||||
Scenario: Car - ignores except restriction
|
||||
Given the extract extra arguments "--parse-conditional-restrictions"
|
||||
@@ -530,6 +599,81 @@ Feature: Car - Turn restrictions
|
||||
| n | p | nj,js,js,jp,jp |
|
||||
| m | p | mj,jp,jp |
|
||||
|
||||
@restriction-way
|
||||
Scenario: Car - prohibit turn
|
||||
Given the extract extra arguments "--parse-conditional-restrictions"
|
||||
# 5pm Wed 02 May, 2017 GMT
|
||||
Given the contract extra arguments "--time-zone-file=test/data/tz/{timezone_names}/guinea.geojson --parse-conditionals-from-now=1493744400"
|
||||
Given the customize extra arguments "--time-zone-file=test/data/tz/{timezone_names}/guinea.geojson --parse-conditionals-from-now=1493744400"
|
||||
|
||||
Given the node map
|
||||
"""
|
||||
c
|
||||
|
|
||||
| f
|
||||
| |
|
||||
b---e
|
||||
| |
|
||||
a d
|
||||
"""
|
||||
|
||||
And the ways
|
||||
| nodes |
|
||||
| ab |
|
||||
| bc |
|
||||
| be |
|
||||
| de |
|
||||
| ef |
|
||||
|
||||
And the relations
|
||||
| type | way:from | way:via | way:to | restriction:conditional |
|
||||
| restriction | ab | be | de | no_right_turn @ (Mo-Fr 07:00-11:00,16:00-18:30) |
|
||||
|
||||
When I route I should get
|
||||
| from | to | route | turns | locations |
|
||||
| a | d | ab,be,ef,ef,de,de | depart,turn right,turn left,continue uturn,new name straight,arrive | a,b,e,f,e,d |
|
||||
| a | f | ab,be,ef,ef | depart,turn right,turn left,arrive | a,b,e,f |
|
||||
| c | d | bc,be,de,de | depart,turn left,turn right,arrive | c,b,e,d |
|
||||
| c | f | bc,be,ef,ef | depart,turn left,turn left,arrive | c,b,e,f |
|
||||
|
||||
# condition is off
|
||||
@restriction-way
|
||||
Scenario: Car - prohibit turn
|
||||
Given the extract extra arguments "--parse-conditional-restrictions"
|
||||
# time stamp for 12am on Tues, 02 May 2017 GMT
|
||||
Given the contract extra arguments "--time-zone-file=test/data/tz/{timezone_names}/guinea.geojson --parse-conditionals-from-now=1493726400"
|
||||
Given the customize extra arguments "--time-zone-file=test/data/tz/{timezone_names}/guinea.geojson --parse-conditionals-from-now=1493726400"
|
||||
|
||||
Given the node map
|
||||
"""
|
||||
c
|
||||
|
|
||||
| f
|
||||
| |
|
||||
b---e
|
||||
| |
|
||||
a d
|
||||
"""
|
||||
|
||||
And the ways
|
||||
| nodes |
|
||||
| ab |
|
||||
| bc |
|
||||
| be |
|
||||
| de |
|
||||
| ef |
|
||||
|
||||
And the relations
|
||||
| type | way:from | way:via | way:to | restriction:conditional |
|
||||
| restriction | ab | be | de | no_right_turn @ (Mo-Fr 07:00-11:00,16:00-18:30) |
|
||||
|
||||
When I route I should get
|
||||
| from | to | route |
|
||||
| a | d | ab,be,de,de |
|
||||
| a | f | ab,be,ef,ef |
|
||||
| c | d | bc,be,de,de |
|
||||
| c | f | bc,be,ef,ef |
|
||||
|
||||
# https://www.openstreetmap.org/#map=18/38.91099/-77.00888
|
||||
@no_turning @conditionals
|
||||
Scenario: Car - DC North capitol situation, two on one off
|
||||
@@ -739,3 +883,175 @@ Feature: Car - Turn restrictions
|
||||
| from | to | route | turns |
|
||||
| a | c | albic,dobe,dobe,albic,albic | depart,turn left,continue uturn,turn left,arrive |
|
||||
| a | e | albic,dobe,dobe | depart,turn left,arrive |
|
||||
|
||||
@no_turning @conditionals
|
||||
Scenario: Car - Conditional restriction with multiple time windows
|
||||
Given the extract extra arguments "--parse-conditional-restrictions"
|
||||
# 5pm Wed 02 May, 2017 GMT
|
||||
Given the contract extra arguments "--time-zone-file=test/data/tz/{timezone_names}/guinea.geojson --parse-conditionals-from-now=1493744400"
|
||||
Given the customize extra arguments "--time-zone-file=test/data/tz/{timezone_names}/guinea.geojson --parse-conditionals-from-now=1493744400"
|
||||
|
||||
Given the node map
|
||||
"""
|
||||
a f
|
||||
| |
|
||||
b - e - h
|
||||
| | |
|
||||
c d - g
|
||||
1
|
||||
"""
|
||||
|
||||
And the ways
|
||||
| nodes |
|
||||
| ab |
|
||||
| bc |
|
||||
| de |
|
||||
| ef |
|
||||
| be |
|
||||
| eh |
|
||||
| gh |
|
||||
| dg |
|
||||
|
||||
And the relations
|
||||
| type | way:from | way:via | way:to | restriction:conditional |
|
||||
| restriction | ab | be | ef | no_uturn @ (Mo-Fr 07:00-11:00,16:00-18:30) |
|
||||
|
||||
And the relations
|
||||
| type | way:from | way:to | node:via | restriction:conditional |
|
||||
| restriction | ed | dg | d | no_uturn @ (Mo-Fr 07:00-11:00,16:00-18:30) |
|
||||
|
||||
When I route I should get
|
||||
| from | to | route |
|
||||
| a | f | ab,bc,bc,be,ef,ef |
|
||||
| f | 1 | ef,eh,gh,dg,dg |
|
||||
|
||||
@restriction-way @overlap
|
||||
Scenario: Car - prohibit turn
|
||||
Given the extract extra arguments "--parse-conditional-restrictions"
|
||||
# 5pm Wed 02 May, 2017 GMT
|
||||
Given the contract extra arguments "--time-zone-file=test/data/tz/{timezone_names}/guinea.geojson --parse-conditionals-from-now=1493744400"
|
||||
Given the customize extra arguments "--time-zone-file=test/data/tz/{timezone_names}/guinea.geojson --parse-conditionals-from-now=1493744400"
|
||||
|
||||
Given the node map
|
||||
"""
|
||||
c
|
||||
|
|
||||
| f
|
||||
| |
|
||||
b---e
|
||||
| |
|
||||
a d
|
||||
"""
|
||||
|
||||
And the ways
|
||||
| nodes |
|
||||
| ab |
|
||||
| bc |
|
||||
| be |
|
||||
| de |
|
||||
| ef |
|
||||
|
||||
And the relations
|
||||
| type | way:from | way:via | way:to | restriction:conditional |
|
||||
| restriction | ab | be | de | no_right_turn @ (Mo-Fr 07:00-11:00) |
|
||||
|
||||
And the relations
|
||||
| type | way:from | way:via | way:to | restriction |
|
||||
| restriction | ab | be | de | no_right_turn |
|
||||
|
||||
# condition is off, but the general restriction should take precedence
|
||||
When I route I should get
|
||||
| from | to | route | turns | locations |
|
||||
| a | d | ab,be,ef,ef,de,de | depart,turn right,turn left,continue uturn,new name straight,arrive | a,b,e,f,e,d |
|
||||
| a | f | ab,be,ef,ef | depart,turn right,turn left,arrive | a,b,e,f |
|
||||
| c | d | bc,be,de,de | depart,turn left,turn right,arrive | c,b,e,d |
|
||||
| c | f | bc,be,ef,ef | depart,turn left,turn left,arrive | c,b,e,f |
|
||||
|
||||
@restriction-way @overlap
|
||||
Scenario: Car - prohibit turn
|
||||
Given the extract extra arguments "--parse-conditional-restrictions"
|
||||
# 5pm Wed 02 May, 2017 GMT
|
||||
Given the contract extra arguments "--time-zone-file=test/data/tz/{timezone_names}/guinea.geojson --parse-conditionals-from-now=1493744400"
|
||||
Given the customize extra arguments "--time-zone-file=test/data/tz/{timezone_names}/guinea.geojson --parse-conditionals-from-now=1493744400"
|
||||
|
||||
Given the node map
|
||||
"""
|
||||
c
|
||||
|
|
||||
| f
|
||||
| |
|
||||
b---e
|
||||
| |
|
||||
| d
|
||||
|
|
||||
a
|
||||
"""
|
||||
|
||||
And the ways
|
||||
| nodes |
|
||||
| ab |
|
||||
| bc |
|
||||
| be |
|
||||
| de |
|
||||
| ef |
|
||||
|
||||
And the relations
|
||||
| type | way:from | way:via | way:to | restriction:conditional |
|
||||
| restriction | ab | be | de | no_right_turn @ (Mo-Fr 07:00-11:00) |
|
||||
|
||||
And the relations
|
||||
| type | way:from | node:via | way:to | restriction:conditional |
|
||||
| restriction | be | e | de | no_right_turn @ (Mo-Fr 16:00-18:00) |
|
||||
|
||||
# way restriction is off, node-restriction is on
|
||||
When I route I should get
|
||||
| from | to | route | turns | locations |
|
||||
| a | d | ab,be,ef,ef,de,de | depart,turn right,turn left,continue uturn,new name straight,arrive | a,b,e,f,e,d |
|
||||
| a | f | ab,be,ef,ef | depart,turn right,turn left,arrive | a,b,e,f |
|
||||
| c | d | bc,be,ef,ef,de,de | depart,turn left,turn left,continue uturn,new name straight,arrive | c,b,e,f,e,d |
|
||||
| c | f | bc,be,ef,ef | depart,turn left,turn left,arrive | c,b,e,f |
|
||||
|
||||
@restriction-way @overlap
|
||||
Scenario: Car - prohibit turn
|
||||
Given the extract extra arguments "--parse-conditional-restrictions"
|
||||
# 5pm Wed 02 May, 2017 GMT
|
||||
Given the contract extra arguments "--time-zone-file=test/data/tz/{timezone_names}/guinea.geojson --parse-conditionals-from-now=1493744400"
|
||||
Given the customize extra arguments "--time-zone-file=test/data/tz/{timezone_names}/guinea.geojson --parse-conditionals-from-now=1493744400"
|
||||
|
||||
Given the node map
|
||||
"""
|
||||
c
|
||||
|
|
||||
| f
|
||||
| |
|
||||
b---e
|
||||
| |
|
||||
| d
|
||||
|
|
||||
a
|
||||
"""
|
||||
|
||||
And the ways
|
||||
| nodes |
|
||||
| ab |
|
||||
| bc |
|
||||
| be |
|
||||
| de |
|
||||
| ef |
|
||||
|
||||
And the relations
|
||||
| type | way:from | way:via | way:to | restriction:conditional |
|
||||
| restriction | ab | be | de | no_right_turn @ (Mo-Fr 16:00-18:00) |
|
||||
|
||||
And the relations
|
||||
| type | way:from | node:via | way:to | restriction:conditional |
|
||||
| restriction | be | e | de | no_right_turn @ (Mo-Fr 07:00-11:00) |
|
||||
|
||||
# node restrictino is off, way restriction is on
|
||||
When I route I should get
|
||||
| from | to | route | turns | locations |
|
||||
| a | d | ab,be,ef,ef,de,de | depart,turn right,turn left,continue uturn,new name straight,arrive | a,b,e,f,e,d |
|
||||
| a | f | ab,be,ef,ef | depart,turn right,turn left,arrive | a,b,e,f |
|
||||
| c | d | bc,be,de,de | depart,turn left,turn right,arrive | c,b,e,d |
|
||||
| c | f | bc,be,ef,ef | depart,turn left,turn left,arrive | c,b,e,f |
|
||||
|
||||
|
||||
@@ -50,6 +50,7 @@ Feature: Car - Handle ferry routes
|
||||
| b | f | abc,cde,efg,efg | driving,ferry,driving,driving | 9 km/h | 162.4s |
|
||||
| c | e | cde,cde | ferry,ferry | 5 km/h | 151.4s |
|
||||
| e | c | cde,cde | ferry,ferry | 5 km/h | 151.4s |
|
||||
|
||||
Scenario: Car - Properly handle simple durations
|
||||
Given the node map
|
||||
"""
|
||||
@@ -91,3 +92,20 @@ Feature: Car - Handle ferry routes
|
||||
| b | f | abc,cde,efg,efg | driving,ferry,driving,driving | 18 km/h | 78.4s |
|
||||
| c | e | cde,cde | ferry,ferry | 11 km/h | 67.4s |
|
||||
| e | c | cde,cde | ferry,ferry | 11 km/h | 67.4s |
|
||||
|
||||
@snapping
|
||||
Scenario: Car - Snapping when using a ferry
|
||||
Given the node map
|
||||
"""
|
||||
a b c d e f
|
||||
"""
|
||||
|
||||
And the ways
|
||||
| nodes | highway | route | duration |
|
||||
| ab | primary | | |
|
||||
| bcde | | ferry | 0:10 |
|
||||
| ef | primary | | |
|
||||
|
||||
When I route I should get
|
||||
| from | to | route | modes | time |
|
||||
| c | d | bcde,bcde | ferry,ferry | 600s |
|
||||
|
||||
@@ -1,44 +0,0 @@
|
||||
@routing @car @mode
|
||||
Feature: Car - Mode flag
|
||||
Background:
|
||||
Given the profile "car"
|
||||
|
||||
Scenario: Car - Mode when using a ferry
|
||||
Given the node map
|
||||
"""
|
||||
a b
|
||||
c d
|
||||
"""
|
||||
|
||||
And the ways
|
||||
| nodes | highway | route | duration |
|
||||
| ab | primary | | |
|
||||
| bc | | ferry | 0:01 |
|
||||
| cd | primary | | |
|
||||
|
||||
When I route I should get
|
||||
| from | to | route | modes |
|
||||
| a | d | ab,bc,cd,cd | driving,ferry,driving,driving |
|
||||
| d | a | cd,bc,ab,ab | driving,ferry,driving,driving |
|
||||
| c | a | bc,ab,ab | ferry,driving,driving |
|
||||
| d | b | cd,bc,bc | driving,ferry,ferry |
|
||||
| a | c | ab,bc,bc | driving,ferry,ferry |
|
||||
| b | d | bc,cd,cd | ferry,driving,driving |
|
||||
|
||||
Scenario: Car - Snapping when using a ferry
|
||||
Given the node map
|
||||
"""
|
||||
a b c d e f
|
||||
"""
|
||||
|
||||
And the ways
|
||||
| nodes | highway | route | duration |
|
||||
| ab | primary | | |
|
||||
| bcde | | ferry | 0:10 |
|
||||
| ef | primary | | |
|
||||
|
||||
When I route I should get
|
||||
| from | to | route | modes | time |
|
||||
| c | d | bcde,bcde | ferry,ferry | 600s |
|
||||
|
||||
|
||||
@@ -5,22 +5,6 @@ Feature: Car - Street names in instructions
|
||||
Given the profile "car"
|
||||
Given a grid size of 5 meters
|
||||
|
||||
Scenario: Car - A named street
|
||||
Given the node map
|
||||
"""
|
||||
a b
|
||||
c
|
||||
"""
|
||||
|
||||
And the ways
|
||||
| nodes | name | ref |
|
||||
| ab | My Way | |
|
||||
| bc | Your Way | A1 |
|
||||
|
||||
When I route I should get
|
||||
| from | to | route | ref |
|
||||
| a | c | My Way,Your Way | ,A1|
|
||||
|
||||
Scenario: Car - A named street with pronunciation
|
||||
Given the node map
|
||||
"""
|
||||
|
||||
@@ -954,11 +954,11 @@ Feature: Car - Turn restrictions
|
||||
# this case is currently not handling the via-way restrictions and we need support for looking across traffic signals.
|
||||
# It is mainly included to show limitations and to prove that we don't crash hard here
|
||||
When I route I should get
|
||||
| from | to | route |
|
||||
| a | d | ab,bge,de,de |
|
||||
| a | f | ab,bge,ef,ef |
|
||||
| c | d | bc,bge,de,de |
|
||||
| c | f | bc,bge,ef,ef |
|
||||
| from | to | route |
|
||||
| a | d | ab,bge,ef,ef,de,de |
|
||||
| a | f | ab,bge,ef,ef |
|
||||
| c | d | bc,bge,de,de |
|
||||
| c | f | bc,bge,de,de,ef,ef |
|
||||
|
||||
# don't crash hard on invalid restrictions
|
||||
@restriction @invalid
|
||||
@@ -991,3 +991,40 @@ Feature: Car - Turn restrictions
|
||||
When I route I should get
|
||||
| from | to | route |
|
||||
| a | f | ab,be,ef,ef |
|
||||
|
||||
|
||||
@restriction @overlap @geometry
|
||||
Scenario: Duplicated restriction
|
||||
Given the node map
|
||||
"""
|
||||
c
|
||||
|
|
||||
| f
|
||||
| |
|
||||
b-g-e
|
||||
| |
|
||||
| d
|
||||
|
|
||||
a
|
||||
"""
|
||||
|
||||
And the ways
|
||||
| nodes |
|
||||
| ab |
|
||||
| bc |
|
||||
| bge |
|
||||
| de |
|
||||
| ef |
|
||||
|
||||
And the relations
|
||||
| type | way:from | way:to | node:via | restriction |
|
||||
| restriction | bge | ef | e | no_left_turn |
|
||||
|
||||
And the relations
|
||||
| type | way:from | way:via | way:to | restriction |
|
||||
| restriction | ab | bge | de | no_right_turn |
|
||||
| restriction | bc | bge | ef | no_left_turn |
|
||||
|
||||
When I route I should get
|
||||
| from | to | route |
|
||||
| a | d | ab,bc,bc,bge,de,de |
|
||||
|
||||
@@ -37,3 +37,57 @@ Feature: Car - Handle traffic lights
|
||||
| 3 | 4 | 13.1s | no turn with traffic light |
|
||||
| g | j | 18.7s | turn with no traffic light |
|
||||
| k | n | 20.7s | turn with traffic light |
|
||||
|
||||
|
||||
Scenario: Tarrif Signal Geometry
|
||||
Given the query options
|
||||
| overview | full |
|
||||
| geometries | polyline |
|
||||
|
||||
Given the node map
|
||||
"""
|
||||
a - b - c
|
||||
"""
|
||||
|
||||
And the ways
|
||||
| nodes | highway |
|
||||
| abc | primary |
|
||||
|
||||
And the nodes
|
||||
| node | highway |
|
||||
| b | traffic_signals |
|
||||
|
||||
When I route I should get
|
||||
| from | to | route | geometry |
|
||||
| a | c | abc,abc | _ibE_ibE?gJ?gJ |
|
||||
|
||||
@traffic
|
||||
Scenario: Traffic update on the edge with a traffic signal
|
||||
Given the node map
|
||||
"""
|
||||
a - b - c
|
||||
"""
|
||||
|
||||
And the ways
|
||||
| nodes | highway |
|
||||
| abc | primary |
|
||||
|
||||
|
||||
And the nodes
|
||||
| node | highway |
|
||||
| b | traffic_signals |
|
||||
|
||||
And the contract extra arguments "--segment-speed-file {speeds_file}"
|
||||
And the customize extra arguments "--segment-speed-file {speeds_file}"
|
||||
And the speed file
|
||||
"""
|
||||
1,2,65
|
||||
2,1,65
|
||||
"""
|
||||
And the query options
|
||||
| annotations | datasources,nodes,speed,duration,weight |
|
||||
|
||||
When I route I should get
|
||||
| from | to | route | speed | weights | time | distances | a:datasources | a:nodes | a:speed | a:duration | a:weight |
|
||||
| a | c | abc,abc | 59 km/h | 24.2,0 | 24.2s | 399.9m,0m | 1:0 | 1:2:3 | 18:18 | 11.1:11.1 | 11.1:11.1 |
|
||||
| c | a | abc,abc | 59 km/h | 24.2,0 | 24.2s | 399.9m,0m | 0:1 | 3:2:1 | 18:18 | 11.1:11.1 | 11.1:11.1 |
|
||||
|
||||
@@ -21,13 +21,7 @@ Feature: Foot - Handle ferry routes
|
||||
When I route I should get
|
||||
| from | to | route | modes |
|
||||
| a | g | abc,cde,efg,efg | walking,ferry,walking,walking |
|
||||
| b | f | abc,cde,efg,efg | walking,ferry,walking,walking |
|
||||
| e | c | cde,cde | ferry,ferry |
|
||||
| e | b | cde,abc,abc | ferry,walking,walking |
|
||||
| e | a | cde,abc,abc | ferry,walking,walking |
|
||||
| c | e | cde,cde | ferry,ferry |
|
||||
| c | f | cde,efg,efg | ferry,walking,walking |
|
||||
| c | g | cde,efg,efg | ferry,walking,walking |
|
||||
|
||||
Scenario: Foot - Ferry duration, single node
|
||||
Given the node map
|
||||
|
||||
@@ -14,25 +14,9 @@ Feature: Foot - Street names in instructions
|
||||
|
||||
And the ways
|
||||
| nodes | name | ref |
|
||||
| ab | My Way | A6 |
|
||||
| bc | Your Way | B7 |
|
||||
| ab | My Way | |
|
||||
| bc | | A7 |
|
||||
|
||||
When I route I should get
|
||||
| from | to | route |
|
||||
| a | c | My Way,Your Way,Your Way |
|
||||
|
||||
@unnamed
|
||||
Scenario: Foot - No longer use way type to describe unnamed ways, see #3231
|
||||
Given the node map
|
||||
"""
|
||||
a b c d
|
||||
"""
|
||||
|
||||
And the ways
|
||||
| nodes | highway | name |
|
||||
| ab | footway | |
|
||||
| bcd | track | |
|
||||
|
||||
When I route I should get
|
||||
| from | to | route |
|
||||
| a | d | , |
|
||||
| from | to | route | ref |
|
||||
| a | c | My Way,, | ,A7,A7 |
|
||||
|
||||
@@ -1,47 +0,0 @@
|
||||
@routing @foot @ref @name
|
||||
Feature: Foot - Way ref
|
||||
|
||||
Background:
|
||||
Given the profile "foot"
|
||||
|
||||
Scenario: Foot - Way with both name and ref
|
||||
Given the node map
|
||||
"""
|
||||
a b
|
||||
"""
|
||||
|
||||
And the ways
|
||||
| nodes | name | ref |
|
||||
| ab | Utopia Drive | E7 |
|
||||
|
||||
When I route I should get
|
||||
| from | to | route | ref |
|
||||
| a | b | Utopia Drive,Utopia Drive | E7,E7 |
|
||||
|
||||
Scenario: Foot - Way with only ref
|
||||
Given the node map
|
||||
"""
|
||||
a b
|
||||
"""
|
||||
|
||||
And the ways
|
||||
| nodes | name | ref |
|
||||
| ab | | E7 |
|
||||
|
||||
When I route I should get
|
||||
| from | to | route | ref |
|
||||
| a | b | , | E7,E7 |
|
||||
|
||||
Scenario: Foot - Way with only name
|
||||
Given the node map
|
||||
"""
|
||||
a b
|
||||
"""
|
||||
|
||||
And the ways
|
||||
| nodes | name |
|
||||
| ab | Utopia Drive |
|
||||
|
||||
When I route I should get
|
||||
| from | to | route |
|
||||
| a | b | Utopia Drive,Utopia Drive |
|
||||
@@ -32,84 +32,6 @@ Feature: Foot - Turn restrictions
|
||||
| s | n | sj,nj,nj |
|
||||
| s | e | sj,ej,ej |
|
||||
|
||||
@no_turning
|
||||
Scenario: Foot - No right turn
|
||||
Given the node map
|
||||
"""
|
||||
n
|
||||
w j e
|
||||
s
|
||||
"""
|
||||
|
||||
And the ways
|
||||
| nodes | oneway |
|
||||
| sj | yes |
|
||||
| nj | -1 |
|
||||
| wj | -1 |
|
||||
| ej | -1 |
|
||||
|
||||
And the relations
|
||||
| type | way:from | way:to | node:via | restriction |
|
||||
| restriction | sj | ej | j | no_right_turn |
|
||||
|
||||
When I route I should get
|
||||
| from | to | route |
|
||||
| s | w | sj,wj,wj |
|
||||
| s | n | sj,nj,nj |
|
||||
| s | e | sj,ej,ej |
|
||||
|
||||
@no_turning
|
||||
Scenario: Foot - No u-turn
|
||||
Given the node map
|
||||
"""
|
||||
n
|
||||
w j e
|
||||
s
|
||||
"""
|
||||
|
||||
And the ways
|
||||
| nodes | oneway |
|
||||
| sj | yes |
|
||||
| nj | -1 |
|
||||
| wj | -1 |
|
||||
| ej | -1 |
|
||||
|
||||
And the relations
|
||||
| type | way:from | way:to | node:via | restriction |
|
||||
| restriction | sj | wj | j | no_u_turn |
|
||||
|
||||
When I route I should get
|
||||
| from | to | route |
|
||||
| s | w | sj,wj,wj |
|
||||
| s | n | sj,nj,nj |
|
||||
| s | e | sj,ej,ej |
|
||||
|
||||
@no_turning
|
||||
Scenario: Foot - Handle any no_* relation
|
||||
Given the node map
|
||||
"""
|
||||
n
|
||||
w j e
|
||||
s
|
||||
"""
|
||||
|
||||
And the ways
|
||||
| nodes | oneway |
|
||||
| sj | yes |
|
||||
| nj | -1 |
|
||||
| wj | -1 |
|
||||
| ej | -1 |
|
||||
|
||||
And the relations
|
||||
| type | way:from | way:to | node:via | restriction |
|
||||
| restriction | sj | wj | j | no_weird_zigzags |
|
||||
|
||||
When I route I should get
|
||||
| from | to | route |
|
||||
| s | w | sj,wj,wj |
|
||||
| s | n | sj,nj,nj |
|
||||
| s | e | sj,ej,ej |
|
||||
|
||||
@only_turning
|
||||
Scenario: Foot - Only left turn
|
||||
Given the node map
|
||||
@@ -136,84 +58,6 @@ Feature: Foot - Turn restrictions
|
||||
| s | n | sj,nj,nj |
|
||||
| s | e | sj,ej,ej |
|
||||
|
||||
@only_turning
|
||||
Scenario: Foot - Only right turn
|
||||
Given the node map
|
||||
"""
|
||||
n
|
||||
w j e
|
||||
s
|
||||
"""
|
||||
|
||||
And the ways
|
||||
| nodes | oneway |
|
||||
| sj | yes |
|
||||
| nj | -1 |
|
||||
| wj | -1 |
|
||||
| ej | -1 |
|
||||
|
||||
And the relations
|
||||
| type | way:from | way:to | node:via | restriction |
|
||||
| restriction | sj | ej | j | only_right_turn |
|
||||
|
||||
When I route I should get
|
||||
| from | to | route |
|
||||
| s | w | sj,wj,wj |
|
||||
| s | n | sj,nj,nj |
|
||||
| s | e | sj,ej,ej |
|
||||
|
||||
@only_turning
|
||||
Scenario: Foot - Only straight on
|
||||
Given the node map
|
||||
"""
|
||||
n
|
||||
w j e
|
||||
s
|
||||
"""
|
||||
|
||||
And the ways
|
||||
| nodes | oneway |
|
||||
| sj | yes |
|
||||
| nj | -1 |
|
||||
| wj | -1 |
|
||||
| ej | -1 |
|
||||
|
||||
And the relations
|
||||
| type | way:from | way:to | node:via | restriction |
|
||||
| restriction | sj | nj | j | only_straight_on |
|
||||
|
||||
When I route I should get
|
||||
| from | to | route |
|
||||
| s | w | sj,wj,wj |
|
||||
| s | n | sj,nj,nj |
|
||||
| s | e | sj,ej,ej |
|
||||
|
||||
@no_turning
|
||||
Scenario: Foot - Handle any only_* restriction
|
||||
Given the node map
|
||||
"""
|
||||
n
|
||||
w j e
|
||||
s
|
||||
"""
|
||||
|
||||
And the ways
|
||||
| nodes | oneway |
|
||||
| sj | yes |
|
||||
| nj | -1 |
|
||||
| wj | -1 |
|
||||
| ej | -1 |
|
||||
|
||||
And the relations
|
||||
| type | way:from | way:to | node:via | restriction |
|
||||
| restriction | sj | nj | j | only_weird_zigzags |
|
||||
|
||||
When I route I should get
|
||||
| from | to | route |
|
||||
| s | w | sj,wj,wj |
|
||||
| s | n | sj,nj,nj |
|
||||
| s | e | sj,ej,ej |
|
||||
|
||||
@except
|
||||
Scenario: Foot - Except tag and on no_ restrictions
|
||||
Given the node map
|
||||
@@ -246,30 +90,6 @@ Feature: Foot - Turn restrictions
|
||||
| s | c | sj,cj,cj |
|
||||
| s | d | sj,dj,dj |
|
||||
|
||||
@except
|
||||
Scenario: Foot - Except tag and on only_ restrictions
|
||||
Given the node map
|
||||
"""
|
||||
a b
|
||||
j
|
||||
s
|
||||
"""
|
||||
|
||||
And the ways
|
||||
| nodes | oneway |
|
||||
| sj | yes |
|
||||
| aj | no |
|
||||
| bj | no |
|
||||
|
||||
And the relations
|
||||
| type | way:from | way:to | node:via | restriction | except |
|
||||
| restriction | sj | aj | j | only_straight_on | foot |
|
||||
|
||||
When I route I should get
|
||||
| from | to | route |
|
||||
| s | a | sj,aj,aj |
|
||||
| s | b | sj,bj,bj |
|
||||
|
||||
@except
|
||||
Scenario: Foot - Multiple except tag values
|
||||
Given the node map
|
||||
|
||||
@@ -1,10 +1,9 @@
|
||||
@routing @foot @roundabout @instruction
|
||||
@routing @foot @roundabout @instruction @todo
|
||||
Feature: Roundabout Instructions
|
||||
|
||||
Background:
|
||||
Given the profile "foot"
|
||||
|
||||
@todo
|
||||
Scenario: Foot - Roundabout instructions
|
||||
# You can walk in both directions on a roundabout, bu the normal roundabout instructions don't
|
||||
# make sense when you're going the opposite way around the roundabout.
|
||||
@@ -27,7 +26,7 @@ Feature: Roundabout Instructions
|
||||
| abcda | roundabout |
|
||||
|
||||
When I route I should get
|
||||
| from | to | route | turns |
|
||||
| from | to | route | turns |
|
||||
| s | t | sa,tb | depart,roundabout-exit-1,arrive |
|
||||
| s | u | sa,uc | depart,roundabout-exit-2,arrive |
|
||||
| s | v | sa,vd | depart,roundabout-exit-3,arrive |
|
||||
|
||||
@@ -52,9 +52,9 @@ Feature: Turn Lane Guidance
|
||||
| dy | | | YSt |
|
||||
|
||||
When I route I should get
|
||||
| waypoints | route | turns | lanes |
|
||||
| a,e | MySt,MySt,MySt,MySt | depart,continue right,turn right,arrive | ,straight:false right:false right:true,left:false right:true, |
|
||||
| e,a | MySt,MySt,MySt,MySt | depart,continue left,turn left,arrive | ,left:true left:false straight:false,left:true right:false, |
|
||||
| waypoints | route | turns | lanes |
|
||||
| a,e | MySt,MySt,MySt,MySt | depart,continue right,continue right,arrive | ,straight:false right:false right:true,left:false right:true, |
|
||||
| e,a | MySt,MySt,MySt,MySt | depart,continue left,continue left,arrive | ,left:true left:false straight:false,left:true right:false, |
|
||||
|
||||
@anticipate
|
||||
Scenario: Anticipate Lane Change for quick same direction turns, changing between streets
|
||||
@@ -780,8 +780,8 @@ Feature: Turn Lane Guidance
|
||||
| dy | | YSt |
|
||||
|
||||
When I route I should get
|
||||
| waypoints | route | turns | lanes |
|
||||
| a,e | MySt,MySt,MySt,MySt | depart,continue right,turn right,arrive | ,straight:false straight:false right:false right:true,left:false right:true, |
|
||||
| waypoints | route | turns | lanes |
|
||||
| a,e | MySt,MySt,MySt,MySt | depart,continue right,continue right,arrive | ,straight:false straight:false right:false right:true,left:false right:true, |
|
||||
|
||||
@anticipate
|
||||
Scenario: Don't Overdo It
|
||||
|
||||
@@ -628,9 +628,9 @@ Feature: Collapse
|
||||
| cf | secondary | bottom |
|
||||
|
||||
When I route I should get
|
||||
| waypoints | turns | route | locations |
|
||||
| a,d | depart,continue right,turn right,arrive | road,road,road,road | a,b,c,d |
|
||||
| d,a | depart,continue left,turn left,arrive | road,road,road,road | d,c,b,a |
|
||||
| waypoints | turns | route | locations |
|
||||
| a,d | depart,continue right,continue right,arrive | road,road,road,road | a,b,c,d |
|
||||
| d,a | depart,continue left,continue left,arrive | road,road,road,road | d,c,b,a |
|
||||
|
||||
Scenario: Forking before a turn
|
||||
Given the node map
|
||||
|
||||
@@ -136,3 +136,24 @@ Feature: Continue Instructions
|
||||
| a,d | abcdefb,abcdefb,abcdefb | depart,continue right,arrive |
|
||||
# continuing right here, since the turn to the left is more expensive
|
||||
| a,e | abcdefb,abcdefb,abcdefb | depart,continue right,arrive |
|
||||
|
||||
Scenario: End-Of-Road Continue
|
||||
Given the node map
|
||||
"""
|
||||
a - b - c
|
||||
|
|
||||
d - e
|
||||
|
|
||||
f
|
||||
"""
|
||||
|
||||
And the ways
|
||||
| nodes | highway | name |
|
||||
| abc | primary | road |
|
||||
| bdf | primary | road |
|
||||
| ed | primary | turn |
|
||||
|
||||
|
||||
When I route I should get
|
||||
| waypoints | route | turns |
|
||||
| e,a | turn,road,road,road | depart,turn right,continue left,arrive |
|
||||
|
||||
@@ -863,8 +863,8 @@ Feature: Slipways and Dedicated Turn Lanes
|
||||
| af | primary | sliproad | yes |
|
||||
|
||||
When I route I should get
|
||||
| waypoints | route | turns | locations |
|
||||
| s,g | main,sliproad,another,another | depart,turn right,turn left,arrive | s,a,f,g |
|
||||
| waypoints | route | turns | locations |
|
||||
| s,g | main,sliproad,another,another | depart,turn right,turn slight left,arrive | s,a,f,g |
|
||||
|
||||
@sliproads:
|
||||
Scenario: Throughabout-Sliproad
|
||||
@@ -944,3 +944,55 @@ Feature: Slipways and Dedicated Turn Lanes
|
||||
When I route I should get
|
||||
| waypoints | route | turns | locations |
|
||||
| a,k | road,,, | depart,turn right,roundabout turn right exit-1,arrive | a,b,h,k |
|
||||
|
||||
@sliproads
|
||||
Scenario: Sliproad with 4 roads at target
|
||||
Given the node map
|
||||
"""
|
||||
d
|
||||
.
|
||||
s . a . b . c . t
|
||||
` . '
|
||||
` . '
|
||||
'.'
|
||||
e
|
||||
.
|
||||
f
|
||||
"""
|
||||
|
||||
And the ways
|
||||
| nodes | highway | name | oneway |
|
||||
| sabct | primary | sabct | |
|
||||
| dbef | primary | dbef | |
|
||||
| ae | primary_link | ae | yes |
|
||||
| ec | primary_link | ec | yes |
|
||||
|
||||
When I route I should get
|
||||
| waypoints | route | turns | locations |
|
||||
| s,f | sabct,dbef,dbef | depart,turn right,arrive | s,a,f |
|
||||
| f,t | dbef,sabct,sabct | depart,turn right,arrive | f,e,t |
|
||||
|
||||
@sliproads
|
||||
Scenario: Sliproad and acute angle (50°) at the main intersection
|
||||
Given the node map
|
||||
"""
|
||||
d
|
||||
/
|
||||
s . a . . b . c
|
||||
` /
|
||||
' /
|
||||
e
|
||||
/
|
||||
f
|
||||
"""
|
||||
|
||||
And the ways
|
||||
| nodes | highway | name | oneway |
|
||||
| sabc | primary | sabc | |
|
||||
| dbef | primary | dbef | |
|
||||
| ae | primary_link | ae | yes |
|
||||
|
||||
|
||||
When I route I should get
|
||||
| waypoints | route | turns | locations |
|
||||
| s,f | sabc,dbef,dbef | depart,turn right,arrive | s,a,f |
|
||||
|
||||
@@ -0,0 +1,102 @@
|
||||
@routing @guidance
|
||||
Feature: Divided road entry
|
||||
|
||||
Background:
|
||||
Given the profile "car"
|
||||
Given a grid size of 5 meters
|
||||
|
||||
Scenario: Join on a divided road named after the main road
|
||||
Given the node map
|
||||
"""
|
||||
a-------b-----c
|
||||
|
|
||||
d-------e-----f
|
||||
|
|
||||
|
|
||||
g
|
||||
"""
|
||||
|
||||
And the ways
|
||||
| nodes | name | highway | oneway |
|
||||
| abc | main st | residential | -1 |
|
||||
| def | main st | residential | yes |
|
||||
| be | main st | residential | |
|
||||
| eg | side st | residential | |
|
||||
|
||||
When I route I should get
|
||||
| waypoints | route | turns |
|
||||
| g,a | side st,main st,main st| depart,end of road left,arrive |
|
||||
|
||||
|
||||
# Similar to previous one, but the joining way is tagged with the side-street name
|
||||
Scenario: Join on a divided road, named after the side street
|
||||
Given the node map
|
||||
"""
|
||||
a-------b-----c
|
||||
|
|
||||
d-------e-----f
|
||||
|
|
||||
|
|
||||
g
|
||||
"""
|
||||
|
||||
And the ways
|
||||
| nodes | name | highway | oneway |
|
||||
| abc | main st | residential | -1 |
|
||||
| def | main st | residential | yes |
|
||||
| beg | side st | residential | |
|
||||
|
||||
When I route I should get
|
||||
| waypoints | route | turns |
|
||||
| g,a | side st,main st,main st| depart,end of road left,arrive |
|
||||
|
||||
|
||||
# Center join named after crossroad
|
||||
Scenario: Crossing a divided road, named after side-street
|
||||
Given the node map
|
||||
"""
|
||||
h
|
||||
|
|
||||
a-------b-----c
|
||||
|
|
||||
d-------e-----f
|
||||
|
|
||||
|
|
||||
g
|
||||
"""
|
||||
|
||||
And the ways
|
||||
| nodes | name | highway | oneway |
|
||||
| abc | main st | residential | -1 |
|
||||
| def | main st | residential | yes |
|
||||
| hbeg | side st | residential | |
|
||||
|
||||
When I route I should get
|
||||
| waypoints | route | turns |
|
||||
| g,a | side st,main st,main st| depart,turn left,arrive |
|
||||
|
||||
# Join named after divided road
|
||||
Scenario: Crossing a divided road, named after main street
|
||||
Given the node map
|
||||
"""
|
||||
h
|
||||
|
|
||||
a-------b-----c
|
||||
|
|
||||
d-------e-----f
|
||||
|
|
||||
|
|
||||
g
|
||||
"""
|
||||
|
||||
And the ways
|
||||
| nodes | name | highway | oneway |
|
||||
| abc | main st | residential | -1 |
|
||||
| def | main st | residential | yes |
|
||||
| be | main st | residential | |
|
||||
| hb | side st | residential | |
|
||||
| eg | side st | residential | |
|
||||
|
||||
When I route I should get
|
||||
| waypoints | route | turns |
|
||||
| g,a | side st,main st,main st| depart,turn left,arrive |
|
||||
@@ -97,5 +97,7 @@ Feature: Simple Turns
|
||||
| ei | left | yes |
|
||||
|
||||
When I route I should get
|
||||
| waypoints | route | turns |
|
||||
| g,a | in,road,road | depart,fork right,arrive |
|
||||
| waypoints | route | turns |
|
||||
| g,a | in,road,road | depart,fork slight right,arrive |
|
||||
| g,h | in,right,right | depart,fork straight,arrive |
|
||||
| g,i | in,left,left | depart,fork slight left,arrive |
|
||||
|
||||
@@ -809,14 +809,14 @@ Feature: Simple Turns
|
||||
|
||||
When I route I should get
|
||||
| waypoints | route | turns | intersections |
|
||||
| a,g | Perle,Heide,Heide | depart,turn right,arrive | true:90;true:90 true:180 false:270 true:345;true:18 |
|
||||
| a,k | Perle,Friede,Friede | depart,turn left,arrive | true:90;true:90 true:180 false:270 true:345;true:153 |
|
||||
| a,e | Perle,Perle | depart,arrive | true:90,true:90 true:180 false:270 true:345;true:270 |
|
||||
| e,k | Perle,Friede,Friede | depart,turn right,arrive | true:270;false:90 true:180 true:270 true:345;true:153 |
|
||||
| e,g | Perle,Heide,Heide | depart,turn left,arrive | true:270;false:90 true:180 true:270 true:345;true:18 |
|
||||
| h,k | Heide,Friede | depart,arrive | true:16,true:90 true:180 true:270 true:345;true:153 |
|
||||
| h,e | Heide,Perle,Perle | depart,turn right,arrive | true:16;true:90 true:180 true:270 true:345;true:270 |
|
||||
| h,a | Heide,Perle,Perle | depart,turn left,arrive | true:16;true:90 true:180 true:270 true:345;true:90 |
|
||||
| a,g | Perle,Heide,Heide | depart,turn right,arrive | true:90;true:90 true:195 false:270 true:345;true:18 |
|
||||
| a,k | Perle,Friede,Friede | depart,turn left,arrive | true:90;true:90 true:195 false:270 true:345;true:153 |
|
||||
| a,e | Perle,Perle | depart,arrive | true:90,true:90 true:195 false:270 true:345;true:270 |
|
||||
| e,k | Perle,Friede,Friede | depart,turn right,arrive | true:270;false:90 true:195 true:270 true:345;true:153 |
|
||||
| e,g | Perle,Heide,Heide | depart,turn left,arrive | true:270;false:90 true:195 true:270 true:345;true:18 |
|
||||
| h,k | Heide,Friede | depart,arrive | true:16,true:90 true:195 true:270 true:345;true:153 |
|
||||
| h,e | Heide,Perle,Perle | depart,turn right,arrive | true:16;true:90 true:195 true:270 true:345;true:270 |
|
||||
| h,a | Heide,Perle,Perle | depart,turn left,arrive | true:16;true:90 true:195 true:270 true:345;true:90 |
|
||||
|
||||
#http://www.openstreetmap.org/#map=19/52.53293/13.32956
|
||||
Scenario: Curved Exit from Curved Road
|
||||
@@ -1006,8 +1006,8 @@ Feature: Simple Turns
|
||||
| waypoints | route | turns |
|
||||
| a,e | Heide,Heide,Heide | depart,continue uturn,arrive |
|
||||
| a,g | Heide,Fenn,Fenn | depart,turn right,arrive |
|
||||
| a,h | Heide,Friede,Friede | depart,turn slight left,arrive |
|
||||
| i,e | Perle,Heide,Heide | depart,turn right,arrive |
|
||||
| a,h | Heide,Friede,Friede | depart,turn left,arrive |
|
||||
| i,e | Perle,Heide,Heide | depart,turn sharp right,arrive |
|
||||
| i,h | Perle,Friede,Friede | depart,turn left,arrive |
|
||||
|
||||
#http://www.openstreetmap.org/#map=19/52.48630/13.36017
|
||||
@@ -1189,7 +1189,7 @@ Feature: Simple Turns
|
||||
|
||||
When I route I should get
|
||||
| waypoints | route | turns |
|
||||
| a,c | rose,trift | depart,arrive |
|
||||
| a,c | rose,trift,trift | depart,turn slight left,arrive |
|
||||
| a,k | rose,muhle,muhle | depart,turn slight right,arrive |
|
||||
| d,f | trift,rose | depart,arrive |
|
||||
| d,k | trift,muhle,muhle | depart,turn sharp left,arrive |
|
||||
|
||||
@@ -835,9 +835,9 @@ Feature: Turn Lane Guidance
|
||||
| cf | secondary | bottom | |
|
||||
|
||||
When I route I should get
|
||||
| waypoints | turns | route | lanes |
|
||||
| a,d | depart,continue right,turn right,arrive | road,road,road,road | ,straight:false right:true,, |
|
||||
| d,a | depart,continue left,turn left,arrive | road,road,road,road | ,left:true straight:false,, |
|
||||
| waypoints | turns | route | lanes |
|
||||
| a,d | depart,continue right,continue right,arrive | road,road,road,road | ,straight:false right:true,, |
|
||||
| d,a | depart,continue left,continue left,arrive | road,road,road,road | ,left:true straight:false,, |
|
||||
|
||||
@simple
|
||||
Scenario: Merge Lanes Onto Freeway
|
||||
|
||||
@@ -788,9 +788,9 @@ Feature: Simple Turns
|
||||
| bg | primary | yes |
|
||||
|
||||
When I route I should get
|
||||
| waypoints | route | turns |
|
||||
| a,d | abc,bd,bd | depart,turn sharp right,arrive |
|
||||
| a,f | abc,bf,bf | depart,turn right,arrive |
|
||||
| waypoints | route | turns |
|
||||
| a,d | abc,bd,bd | depart,turn right,arrive |
|
||||
| a,f | abc,bf,bf | depart,turn slight right,arrive |
|
||||
|
||||
Scenario: Right Turn Assignment Three Conflicting Turns with invalid - 3
|
||||
Given the node map
|
||||
|
||||
@@ -1,35 +0,0 @@
|
||||
@routing @datastore @testbot
|
||||
Feature: Temporary tests related to osrm-datastore
|
||||
|
||||
Background:
|
||||
Given the profile "testbot"
|
||||
|
||||
Scenario: Scenario ab
|
||||
Given the node map
|
||||
"""
|
||||
a b
|
||||
"""
|
||||
|
||||
And the ways
|
||||
| nodes |
|
||||
| ab |
|
||||
|
||||
When I route I should get
|
||||
| from | to | route |
|
||||
| a | b | ab,ab |
|
||||
| b | a | ab,ab |
|
||||
|
||||
Scenario: Scenaria xy
|
||||
Given the node map
|
||||
"""
|
||||
x y
|
||||
"""
|
||||
|
||||
And the ways
|
||||
| nodes |
|
||||
| xy |
|
||||
|
||||
When I route I should get
|
||||
| from | to | route |
|
||||
| x | y | xy,xy |
|
||||
| y | x | xy,xy |
|
||||
@@ -226,23 +226,3 @@ Feature: Distance calculation
|
||||
| x | v | xv,xv | 424m +-1 |
|
||||
| x | w | xw,xw | 360m +-1 |
|
||||
| x | y | xy,xy | 316m +-1 |
|
||||
|
||||
@maze
|
||||
Scenario: Distance of a maze of short segments
|
||||
Given a grid size of 7 meters
|
||||
Given the node map
|
||||
"""
|
||||
a b s t
|
||||
d c r q
|
||||
e f o p
|
||||
h g n m
|
||||
i j k l
|
||||
"""
|
||||
|
||||
And the ways
|
||||
| nodes |
|
||||
| abcdefghijklmnopqrst |
|
||||
|
||||
When I route I should get
|
||||
| from | to | route | distance |
|
||||
| a | t | abcdefghijklmnopqrst,abcdefghijklmnopqrst | 133m +-1 |
|
||||
|
||||
@@ -21,12 +21,12 @@ Feature: Durations
|
||||
| ef | primary | 01:02:03 |
|
||||
|
||||
When I route I should get
|
||||
| from | to | route | distance | time |
|
||||
| a | b | ab,ab | 100m +-1 | 60s +-1 |
|
||||
| b | c | bc,bc | 200m +-1 | 600s +-1 |
|
||||
| c | d | cd,cd | 300m +-1 | 3600s +-1 |
|
||||
| d | e | de,de | 141m +-2 | 36000s +-1 |
|
||||
| e | f | ef,ef | 224m +-2 | 3723s +-1 |
|
||||
| from | to | route | time |
|
||||
| a | b | ab,ab | 60s +-1 |
|
||||
| b | c | bc,bc | 600s +-1 |
|
||||
| c | d | cd,cd | 3600s +-1 |
|
||||
| d | e | de,de | 36000s +-1 |
|
||||
| e | f | ef,ef | 3723s +-1 |
|
||||
|
||||
@todo
|
||||
Scenario: Partial duration of ways
|
||||
@@ -40,7 +40,7 @@ Feature: Durations
|
||||
| abc | primary | 0:01 |
|
||||
|
||||
When I route I should get
|
||||
| from | to | route | distance | time |
|
||||
| a | c | abc,abc | 300m +-1 | 60s +-1 |
|
||||
| a | b | ab,ab | 100m +-1 | 20s +-1 |
|
||||
| b | c | bc,bc | 200m +-1 | 40s +-1 |
|
||||
| from | to | route | time |
|
||||
| a | c | abc,abc | 60s +-1 |
|
||||
| a | b | ab,ab | 20s +-1 |
|
||||
| b | c | bc,bc | 40s +-1 |
|
||||
|
||||
@@ -5,51 +5,6 @@ Feature: Testbot - oneways
|
||||
Given the profile "testbot"
|
||||
Given a grid size of 250 meters
|
||||
|
||||
Scenario: Routing on a oneway roundabout
|
||||
Given the node map
|
||||
"""
|
||||
v
|
||||
x d c
|
||||
e b
|
||||
f a
|
||||
g h y
|
||||
z
|
||||
"""
|
||||
|
||||
And the ways
|
||||
| nodes | oneway |
|
||||
| ab | yes |
|
||||
| bc | yes |
|
||||
| cd | yes |
|
||||
| de | yes |
|
||||
| ef | yes |
|
||||
| fg | yes |
|
||||
| gh | yes |
|
||||
| ha | yes |
|
||||
| vx | yes |
|
||||
| vy | yes |
|
||||
| yz | yes |
|
||||
| xe | yes |
|
||||
|
||||
When I route I should get
|
||||
| from | to | route |
|
||||
| a | b | ab,ab |
|
||||
| b | c | bc,bc |
|
||||
| c | d | cd,cd |
|
||||
| d | e | de,de |
|
||||
| e | f | ef,ef |
|
||||
| f | g | fg,fg |
|
||||
| g | h | gh,gh |
|
||||
| h | a | ha,ha |
|
||||
| b | a | bc,cd,de,ef,fg,gh,ha,ha |
|
||||
| c | b | cd,de,ef,fg,gh,ha,ab,ab |
|
||||
| d | c | de,ef,fg,gh,ha,ab,bc,bc |
|
||||
| e | d | ef,fg,gh,ha,ab,bc,cd,cd |
|
||||
| f | e | fg,gh,ha,ab,bc,cd,de,de |
|
||||
| g | f | gh,ha,ab,bc,cd,de,ef,ef |
|
||||
| h | g | ha,ab,bc,cd,de,ef,fg,fg |
|
||||
| a | h | ab,bc,cd,de,ef,fg,gh,gh |
|
||||
|
||||
Scenario: Testbot - Simple oneway
|
||||
Then routability should be
|
||||
| highway | foot | oneway | forw | backw |
|
||||
@@ -60,27 +15,6 @@ Feature: Testbot - oneways
|
||||
| highway | foot | oneway | forw | backw |
|
||||
| primary | no | -1 | | x |
|
||||
|
||||
Scenario: Testbot - Around the Block
|
||||
Given the node map
|
||||
"""
|
||||
a b
|
||||
e d c f
|
||||
"""
|
||||
|
||||
And the ways
|
||||
| nodes | oneway | foot |
|
||||
| ab | yes | no |
|
||||
| bc | | no |
|
||||
| cd | | no |
|
||||
| da | | no |
|
||||
| de | | no |
|
||||
| cf | | no |
|
||||
|
||||
When I route I should get
|
||||
| from | to | route |
|
||||
| a | b | ab,ab |
|
||||
| b | a | bc,cd,da,da |
|
||||
|
||||
Scenario: Testbot - Handle various oneway tag values
|
||||
Then routability should be
|
||||
| foot | oneway | forw | backw |
|
||||
@@ -93,19 +27,3 @@ Feature: Testbot - oneways
|
||||
| no | true | x | |
|
||||
| no | 1 | x | |
|
||||
| no | -1 | | x |
|
||||
|
||||
Scenario: Testbot - Two consecutive oneways
|
||||
Given the node map
|
||||
"""
|
||||
a b c
|
||||
"""
|
||||
|
||||
And the ways
|
||||
| nodes | oneway |
|
||||
| ab | yes |
|
||||
| bc | yes |
|
||||
|
||||
|
||||
When I route I should get
|
||||
| from | to | route |
|
||||
| a | c | ab,bc,bc |
|
||||
|
||||
@@ -26,6 +26,33 @@ Feature: Penalties
|
||||
| a | c | abc,abc | 20s +-1 | 200m +-1 |
|
||||
| d | f | def,def | 27s +-1 | 200m +-1 |
|
||||
|
||||
# Penalties not on the phantom nodes
|
||||
Scenario: Traffic signals should incur a delay, without changing distance
|
||||
Given the node map
|
||||
"""
|
||||
a b c d e
|
||||
f g h i j
|
||||
"""
|
||||
|
||||
And the nodes
|
||||
| node | highway |
|
||||
| c | traffic_signals |
|
||||
|
||||
And the ways
|
||||
| nodes |
|
||||
| ab |
|
||||
| bcd |
|
||||
| de |
|
||||
| fg |
|
||||
| ghi |
|
||||
| ij |
|
||||
|
||||
When I route I should get
|
||||
| from | to | route | time | distance |
|
||||
| a | e | ab,bcd,de | 47s +-1 | 400m +-1 |
|
||||
| f | j | fg,ghi,ij | 40s +-1 | 400m +-1 |
|
||||
|
||||
|
||||
Scenario: Signal penalty should not depend on way type
|
||||
Given the node map
|
||||
"""
|
||||
@@ -72,55 +99,35 @@ Feature: Penalties
|
||||
| from | to | route | time |
|
||||
| a | e | abcde,abcde | 61s +-1 |
|
||||
|
||||
@todo
|
||||
Scenario: Signal penalty should not depend on way type
|
||||
Given the node map
|
||||
"""
|
||||
a b c
|
||||
d e f
|
||||
g h i
|
||||
"""
|
||||
@todo
|
||||
Scenario: Signal penalty should not depend on way type
|
||||
Given the node map
|
||||
"""
|
||||
a b c
|
||||
d e f
|
||||
g h i
|
||||
"""
|
||||
|
||||
And the nodes
|
||||
| node | highway |
|
||||
| b | traffic_signals |
|
||||
| e | traffic_signals |
|
||||
| h | traffic_signals |
|
||||
And the nodes
|
||||
| node | highway |
|
||||
| b | traffic_signals |
|
||||
| e | traffic_signals |
|
||||
| h | traffic_signals |
|
||||
|
||||
And the ways
|
||||
| nodes | highway |
|
||||
| abc | primary |
|
||||
| def | secondary |
|
||||
| ghi | tertiary |
|
||||
And the ways
|
||||
| nodes | highway |
|
||||
| abc | primary |
|
||||
| def | secondary |
|
||||
| ghi | tertiary |
|
||||
|
||||
When I route I should get
|
||||
| from | to | route | time |
|
||||
| a | b | abc,abc | 10s +-1 |
|
||||
| a | c | abc,abc | 27s +-1 |
|
||||
| d | e | def,def | 20s +-1 |
|
||||
| d | f | def,def | 47s +-1 |
|
||||
| g | h | ghi,ghi | 30s +-1 |
|
||||
| g | i | ghi,ghi | 67s +-1 |
|
||||
|
||||
Scenario: Passing multiple traffic signals should incur a accumulated delay
|
||||
Given the node map
|
||||
"""
|
||||
a b c d e
|
||||
"""
|
||||
|
||||
And the nodes
|
||||
| node | highway |
|
||||
| b | traffic_signals |
|
||||
| c | traffic_signals |
|
||||
| d | traffic_signals |
|
||||
|
||||
And the ways
|
||||
| nodes |
|
||||
| abcde |
|
||||
|
||||
When I route I should get
|
||||
| from | to | route | time |
|
||||
| a | e | abcde,abcde | 61s +-1 |
|
||||
When I route I should get
|
||||
| from | to | route | time |
|
||||
| a | b | abc,abc | 10s +-1 |
|
||||
| a | c | abc,abc | 27s +-1 |
|
||||
| d | e | def,def | 20s +-1 |
|
||||
| d | f | def,def | 47s +-1 |
|
||||
| g | h | ghi,ghi | 30s +-1 |
|
||||
| g | i | ghi,ghi | 67s +-1 |
|
||||
|
||||
@todo
|
||||
Scenario: Starting or ending at a traffic signal should not incur a delay
|
||||
|
||||
@@ -1,13 +1,6 @@
|
||||
#ifndef OSRM_ENGINE_DATAFACADE_DATAFACADE_HPP
|
||||
#define OSRM_ENGINE_DATAFACADE_DATAFACADE_HPP
|
||||
|
||||
#ifdef OSRM_EXTERNAL_MEMORY
|
||||
|
||||
// Register your own data backend here
|
||||
#error "No external memory implementation found"
|
||||
|
||||
#else
|
||||
|
||||
#include "engine/datafacade/contiguous_internalmem_datafacade.hpp"
|
||||
|
||||
namespace osrm
|
||||
@@ -22,5 +15,3 @@ using DataFacade = datafacade::ContiguousInternalMemoryDataFacade<AlgorithmT>;
|
||||
}
|
||||
|
||||
#endif
|
||||
|
||||
#endif
|
||||
|
||||
@@ -11,6 +11,7 @@
|
||||
#include "util/coordinate.hpp"
|
||||
#include "util/coordinate_calculation.hpp"
|
||||
|
||||
#include <algorithm>
|
||||
#include <utility>
|
||||
#include <vector>
|
||||
|
||||
@@ -20,7 +21,6 @@ namespace engine
|
||||
{
|
||||
namespace guidance
|
||||
{
|
||||
|
||||
// Extracts the geometry for each segment and calculates the traveled distance
|
||||
// Combines the geometry form the phantom node with the PathData
|
||||
// to the full route geometry.
|
||||
@@ -53,9 +53,9 @@ inline LegGeometry assembleGeometry(const datafacade::BaseDataFacade &facade,
|
||||
source_node.fwd_segment_position + (reversed_source ? 1 : 0);
|
||||
const auto source_node_id =
|
||||
reversed_source ? source_node.reverse_segment_id.id : source_node.forward_segment_id.id;
|
||||
const auto source_gemetry_id = facade.GetGeometryIndex(source_node_id).id;
|
||||
const std::vector<NodeID> source_geometry =
|
||||
facade.GetUncompressedForwardGeometry(source_gemetry_id);
|
||||
const auto source_geometry_id = facade.GetGeometryIndex(source_node_id).id;
|
||||
std::vector<NodeID> source_geometry = facade.GetUncompressedForwardGeometry(source_geometry_id);
|
||||
|
||||
geometry.osm_node_ids.push_back(
|
||||
facade.GetOSMNodeIDOfNode(source_geometry[source_segment_start_coordinate]));
|
||||
|
||||
@@ -78,21 +78,26 @@ inline LegGeometry assembleGeometry(const datafacade::BaseDataFacade &facade,
|
||||
}
|
||||
|
||||
prev_coordinate = coordinate;
|
||||
geometry.annotations.emplace_back(LegGeometry::Annotation{
|
||||
current_distance,
|
||||
// NOTE: we want annotations to include only the duration/weight
|
||||
// of the segment itself. For segments immediately before
|
||||
// a turn, the duration_until_turn/weight_until_turn values
|
||||
// include the turn cost. To counter this, we subtract
|
||||
// the duration_of_turn/weight_of_turn value, which is 0 for
|
||||
// non-preceeding-turn segments, but contains the turn value
|
||||
// for segments before a turn.
|
||||
(path_point.duration_until_turn - path_point.duration_of_turn) / 10.,
|
||||
(path_point.weight_until_turn - path_point.weight_of_turn) /
|
||||
facade.GetWeightMultiplier(),
|
||||
path_point.datasource_id});
|
||||
geometry.locations.push_back(std::move(coordinate));
|
||||
geometry.osm_node_ids.push_back(facade.GetOSMNodeIDOfNode(path_point.turn_via_node));
|
||||
|
||||
const auto osm_node_id = facade.GetOSMNodeIDOfNode(path_point.turn_via_node);
|
||||
if (osm_node_id != geometry.osm_node_ids.back())
|
||||
{
|
||||
geometry.annotations.emplace_back(LegGeometry::Annotation{
|
||||
current_distance,
|
||||
// NOTE: we want annotations to include only the duration/weight
|
||||
// of the segment itself. For segments immediately before
|
||||
// a turn, the duration_until_turn/weight_until_turn values
|
||||
// include the turn cost. To counter this, we subtract
|
||||
// the duration_of_turn/weight_of_turn value, which is 0 for
|
||||
// non-preceeding-turn segments, but contains the turn value
|
||||
// for segments before a turn.
|
||||
(path_point.duration_until_turn - path_point.duration_of_turn) / 10.,
|
||||
(path_point.weight_until_turn - path_point.weight_of_turn) /
|
||||
facade.GetWeightMultiplier(),
|
||||
path_point.datasource_id});
|
||||
geometry.locations.push_back(std::move(coordinate));
|
||||
geometry.osm_node_ids.push_back(osm_node_id);
|
||||
}
|
||||
}
|
||||
current_distance =
|
||||
util::coordinate_calculation::haversineDistance(prev_coordinate, target_node.location);
|
||||
@@ -102,9 +107,9 @@ inline LegGeometry assembleGeometry(const datafacade::BaseDataFacade &facade,
|
||||
|
||||
const auto target_node_id =
|
||||
reversed_target ? target_node.reverse_segment_id.id : target_node.forward_segment_id.id;
|
||||
const auto target_gemetry_id = facade.GetGeometryIndex(target_node_id).id;
|
||||
const auto target_geometry_id = facade.GetGeometryIndex(target_node_id).id;
|
||||
const std::vector<DatasourceID> forward_datasources =
|
||||
facade.GetUncompressedForwardDatasources(target_gemetry_id);
|
||||
facade.GetUncompressedForwardDatasources(target_geometry_id);
|
||||
|
||||
// FIXME if source and target phantoms are on the same segment then duration and weight
|
||||
// will be from one projected point till end of segment
|
||||
@@ -127,7 +132,7 @@ inline LegGeometry assembleGeometry(const datafacade::BaseDataFacade &facade,
|
||||
const auto target_segment_end_coordinate =
|
||||
target_node.fwd_segment_position + (reversed_target ? 0 : 1);
|
||||
const std::vector<NodeID> target_geometry =
|
||||
facade.GetUncompressedForwardGeometry(target_gemetry_id);
|
||||
facade.GetUncompressedForwardGeometry(target_geometry_id);
|
||||
geometry.osm_node_ids.push_back(
|
||||
facade.GetOSMNodeIDOfNode(target_geometry[target_segment_end_coordinate]));
|
||||
|
||||
|
||||
@@ -1,10 +1,14 @@
|
||||
#ifndef RAW_ROUTE_DATA_H
|
||||
#define RAW_ROUTE_DATA_H
|
||||
|
||||
#include "extractor/class_data.hpp"
|
||||
#include "extractor/guidance/turn_instruction.hpp"
|
||||
#include "extractor/travel_mode.hpp"
|
||||
|
||||
#include "engine/phantom_node.hpp"
|
||||
|
||||
#include "osrm/coordinate.hpp"
|
||||
|
||||
#include "util/guidance/entry_class.hpp"
|
||||
#include "util/guidance/turn_bearing.hpp"
|
||||
#include "util/guidance/turn_lanes.hpp"
|
||||
|
||||
@@ -5,9 +5,6 @@
|
||||
#include "engine/plugins/plugin_base.hpp"
|
||||
#include "engine/routing_algorithms.hpp"
|
||||
|
||||
#include "engine/map_matching/bayes_classifier.hpp"
|
||||
#include "engine/routing_algorithms/map_matching.hpp"
|
||||
#include "engine/routing_algorithms/shortest_path.hpp"
|
||||
#include "util/json_util.hpp"
|
||||
|
||||
#include <vector>
|
||||
|
||||
@@ -5,8 +5,7 @@
|
||||
|
||||
#include "engine/api/table_parameters.hpp"
|
||||
#include "engine/routing_algorithms.hpp"
|
||||
#include "engine/routing_algorithms/many_to_many.hpp"
|
||||
#include "engine/search_engine_data.hpp"
|
||||
|
||||
#include "util/json_container.hpp"
|
||||
|
||||
namespace osrm
|
||||
|
||||
@@ -3,10 +3,9 @@
|
||||
|
||||
#include "engine/plugins/plugin_base.hpp"
|
||||
|
||||
#include "engine/api/route_api.hpp"
|
||||
#include "engine/datafacade/datafacade_base.hpp"
|
||||
#include "engine/api/route_parameters.hpp"
|
||||
#include "engine/routing_algorithms.hpp"
|
||||
#include "engine/search_engine_data.hpp"
|
||||
|
||||
#include "util/json_container.hpp"
|
||||
|
||||
#include <cstdlib>
|
||||
|
||||
@@ -134,23 +134,13 @@ void annotatePath(const FacadeT &facade,
|
||||
BOOST_ASSERT(phantom_node_pair.target_phantom.forward_segment_id.id == target_node_id ||
|
||||
phantom_node_pair.target_phantom.reverse_segment_id.id == target_node_id);
|
||||
|
||||
auto node_from = unpacked_nodes.begin(), node_last = std::prev(unpacked_nodes.end());
|
||||
for (auto edge = unpacked_edges.begin(); node_from != node_last; ++node_from, ++edge)
|
||||
{
|
||||
const auto &edge_data = facade.GetEdgeData(*edge);
|
||||
const auto turn_id = edge_data.turn_id; // edge-based graph edge index
|
||||
const auto node_id = *node_from; // edge-based graph node index
|
||||
const auto name_index = facade.GetNameIndex(node_id);
|
||||
const auto turn_instruction = facade.GetTurnInstructionForEdgeID(turn_id);
|
||||
const extractor::TravelMode travel_mode = facade.GetTravelMode(node_id);
|
||||
const auto classes = facade.GetClassData(node_id);
|
||||
// datastructures to hold extracted data from geometry
|
||||
std::vector<NodeID> id_vector;
|
||||
std::vector<EdgeWeight> weight_vector;
|
||||
std::vector<EdgeWeight> duration_vector;
|
||||
std::vector<DatasourceID> datasource_vector;
|
||||
|
||||
const auto geometry_index = facade.GetGeometryIndex(node_id);
|
||||
std::vector<NodeID> id_vector;
|
||||
|
||||
std::vector<EdgeWeight> weight_vector;
|
||||
std::vector<EdgeWeight> duration_vector;
|
||||
std::vector<DatasourceID> datasource_vector;
|
||||
const auto get_segment_geometry = [&](const auto geometry_index) {
|
||||
if (geometry_index.forward)
|
||||
{
|
||||
id_vector = facade.GetUncompressedForwardGeometry(geometry_index.id);
|
||||
@@ -165,6 +155,22 @@ void annotatePath(const FacadeT &facade,
|
||||
duration_vector = facade.GetUncompressedReverseDurations(geometry_index.id);
|
||||
datasource_vector = facade.GetUncompressedReverseDatasources(geometry_index.id);
|
||||
}
|
||||
};
|
||||
|
||||
auto node_from = unpacked_nodes.begin(), node_last = std::prev(unpacked_nodes.end());
|
||||
for (auto edge = unpacked_edges.begin(); node_from != node_last; ++node_from, ++edge)
|
||||
{
|
||||
const auto &edge_data = facade.GetEdgeData(*edge);
|
||||
const auto turn_id = edge_data.turn_id; // edge-based graph edge index
|
||||
const auto node_id = *node_from; // edge-based graph node index
|
||||
const auto name_index = facade.GetNameIndex(node_id);
|
||||
const auto turn_instruction = facade.GetTurnInstructionForEdgeID(turn_id);
|
||||
const extractor::TravelMode travel_mode = facade.GetTravelMode(node_id);
|
||||
const auto classes = facade.GetClassData(node_id);
|
||||
|
||||
const auto geometry_index = facade.GetGeometryIndex(node_id);
|
||||
get_segment_geometry(geometry_index);
|
||||
|
||||
BOOST_ASSERT(id_vector.size() > 0);
|
||||
BOOST_ASSERT(datasource_vector.size() > 0);
|
||||
BOOST_ASSERT(weight_vector.size() == id_vector.size() - 1);
|
||||
@@ -216,21 +222,14 @@ void annotatePath(const FacadeT &facade,
|
||||
}
|
||||
|
||||
std::size_t start_index = 0, end_index = 0;
|
||||
std::vector<unsigned> id_vector;
|
||||
std::vector<EdgeWeight> weight_vector;
|
||||
std::vector<EdgeWeight> duration_vector;
|
||||
std::vector<DatasourceID> datasource_vector;
|
||||
const auto source_geometry_id = facade.GetGeometryIndex(source_node_id).id;
|
||||
const auto target_geometry_id = facade.GetGeometryIndex(target_node_id).id;
|
||||
const auto is_local_path = source_geometry_id == target_geometry_id && unpacked_path.empty();
|
||||
const auto target_geometry = facade.GetGeometryIndex(target_node_id);
|
||||
const auto is_local_path = source_geometry_id == target_geometry.id && unpacked_path.empty();
|
||||
|
||||
get_segment_geometry(target_geometry);
|
||||
|
||||
if (target_traversed_in_reverse)
|
||||
{
|
||||
id_vector = facade.GetUncompressedReverseGeometry(target_geometry_id);
|
||||
weight_vector = facade.GetUncompressedReverseWeights(target_geometry_id);
|
||||
duration_vector = facade.GetUncompressedReverseDurations(target_geometry_id);
|
||||
datasource_vector = facade.GetUncompressedReverseDatasources(target_geometry_id);
|
||||
|
||||
if (is_local_path)
|
||||
{
|
||||
start_index =
|
||||
@@ -246,11 +245,6 @@ void annotatePath(const FacadeT &facade,
|
||||
start_index = phantom_node_pair.source_phantom.fwd_segment_position;
|
||||
}
|
||||
end_index = phantom_node_pair.target_phantom.fwd_segment_position;
|
||||
|
||||
id_vector = facade.GetUncompressedForwardGeometry(target_geometry_id);
|
||||
weight_vector = facade.GetUncompressedForwardWeights(target_geometry_id);
|
||||
duration_vector = facade.GetUncompressedForwardDurations(target_geometry_id);
|
||||
datasource_vector = facade.GetUncompressedForwardDatasources(target_geometry_id);
|
||||
}
|
||||
|
||||
// Given the following compressed geometry:
|
||||
@@ -308,24 +302,6 @@ void annotatePath(const FacadeT &facade,
|
||||
unpacked_path.front().duration_until_turn =
|
||||
std::max(unpacked_path.front().duration_until_turn - source_duration, 0);
|
||||
}
|
||||
|
||||
// there is no equivalent to a node-based node in an edge-expanded graph.
|
||||
// two equivalent routes may start (or end) at different node-based edges
|
||||
// as they are added with the offset how much "weight" on the edge
|
||||
// has already been traversed. Depending on offset one needs to remove
|
||||
// the last node.
|
||||
if (unpacked_path.size() > 1)
|
||||
{
|
||||
const std::size_t last_index = unpacked_path.size() - 1;
|
||||
const std::size_t second_to_last_index = last_index - 1;
|
||||
|
||||
if (unpacked_path[last_index].turn_via_node ==
|
||||
unpacked_path[second_to_last_index].turn_via_node)
|
||||
{
|
||||
unpacked_path.pop_back();
|
||||
}
|
||||
BOOST_ASSERT(!unpacked_path.empty());
|
||||
}
|
||||
}
|
||||
|
||||
template <typename Algorithm>
|
||||
|
||||
@@ -30,7 +30,8 @@ namespace
|
||||
// Unrestricted search (Args is const PhantomNodes &):
|
||||
// * use partition.GetQueryLevel to find the node query level based on source and target phantoms
|
||||
// * allow to traverse all cells
|
||||
inline LevelID getNodeQueryLevel(const partition::MultiLevelPartitionView &partition,
|
||||
template <typename MultiLevelPartition>
|
||||
inline LevelID getNodeQueryLevel(const MultiLevelPartition &partition,
|
||||
NodeID node,
|
||||
const PhantomNodes &phantom_nodes)
|
||||
{
|
||||
@@ -54,8 +55,8 @@ inline bool checkParentCellRestriction(CellID, const PhantomNodes &) { return tr
|
||||
// Restricted search (Args is LevelID, CellID):
|
||||
// * use the fixed level for queries
|
||||
// * check if the node cell is the same as the specified parent onr
|
||||
inline LevelID
|
||||
getNodeQueryLevel(const partition::MultiLevelPartitionView &, NodeID, LevelID level, CellID)
|
||||
template <typename MultiLevelPartition>
|
||||
inline LevelID getNodeQueryLevel(const MultiLevelPartition &, NodeID, LevelID level, CellID)
|
||||
{
|
||||
return level;
|
||||
}
|
||||
@@ -130,10 +131,10 @@ retrievePackedPathFromHeap(const SearchEngineData<Algorithm>::QueryHeap &forward
|
||||
return packed_path;
|
||||
}
|
||||
|
||||
template <bool DIRECTION, typename... Args>
|
||||
template <bool DIRECTION, typename Algorithm, typename... Args>
|
||||
void routingStep(const DataFacade<Algorithm> &facade,
|
||||
SearchEngineData<Algorithm>::QueryHeap &forward_heap,
|
||||
SearchEngineData<Algorithm>::QueryHeap &reverse_heap,
|
||||
typename SearchEngineData<Algorithm>::QueryHeap &forward_heap,
|
||||
typename SearchEngineData<Algorithm>::QueryHeap &reverse_heap,
|
||||
NodeID &middle_node,
|
||||
EdgeWeight &path_upper_bound,
|
||||
const bool force_loop_forward,
|
||||
@@ -260,11 +261,11 @@ using UnpackedNodes = std::vector<NodeID>;
|
||||
using UnpackedEdges = std::vector<EdgeID>;
|
||||
using UnpackedPath = std::tuple<EdgeWeight, UnpackedNodes, UnpackedEdges>;
|
||||
|
||||
template <typename... Args>
|
||||
template <typename Algorithm, typename... Args>
|
||||
UnpackedPath search(SearchEngineData<Algorithm> &engine_working_data,
|
||||
const DataFacade<Algorithm> &facade,
|
||||
SearchEngineData<Algorithm>::QueryHeap &forward_heap,
|
||||
SearchEngineData<Algorithm>::QueryHeap &reverse_heap,
|
||||
typename SearchEngineData<Algorithm>::QueryHeap &forward_heap,
|
||||
typename SearchEngineData<Algorithm>::QueryHeap &reverse_heap,
|
||||
const bool force_loop_forward,
|
||||
const bool force_loop_reverse,
|
||||
EdgeWeight weight_upper_bound,
|
||||
@@ -389,10 +390,11 @@ UnpackedPath search(SearchEngineData<Algorithm> &engine_working_data,
|
||||
}
|
||||
|
||||
// Alias to be compatible with the CH-based search
|
||||
template <typename Algorithm>
|
||||
inline void search(SearchEngineData<Algorithm> &engine_working_data,
|
||||
const DataFacade<Algorithm> &facade,
|
||||
SearchEngineData<Algorithm>::QueryHeap &forward_heap,
|
||||
SearchEngineData<Algorithm>::QueryHeap &reverse_heap,
|
||||
typename SearchEngineData<Algorithm>::QueryHeap &forward_heap,
|
||||
typename SearchEngineData<Algorithm>::QueryHeap &reverse_heap,
|
||||
EdgeWeight &weight,
|
||||
std::vector<NodeID> &unpacked_nodes,
|
||||
const bool force_loop_forward,
|
||||
@@ -442,13 +444,14 @@ void unpackPath(const FacadeT &facade,
|
||||
annotatePath(facade, phantom_nodes, unpacked_nodes, unpacked_edges, unpacked_path);
|
||||
}
|
||||
|
||||
inline double getNetworkDistance(SearchEngineData<Algorithm> &engine_working_data,
|
||||
const DataFacade<Algorithm> &facade,
|
||||
SearchEngineData<Algorithm>::QueryHeap &forward_heap,
|
||||
SearchEngineData<Algorithm>::QueryHeap &reverse_heap,
|
||||
const PhantomNode &source_phantom,
|
||||
const PhantomNode &target_phantom,
|
||||
EdgeWeight weight_upper_bound = INVALID_EDGE_WEIGHT)
|
||||
template <typename Algorithm>
|
||||
double getNetworkDistance(SearchEngineData<Algorithm> &engine_working_data,
|
||||
const DataFacade<Algorithm> &facade,
|
||||
typename SearchEngineData<Algorithm>::QueryHeap &forward_heap,
|
||||
typename SearchEngineData<Algorithm>::QueryHeap &reverse_heap,
|
||||
const PhantomNode &source_phantom,
|
||||
const PhantomNode &target_phantom,
|
||||
EdgeWeight weight_upper_bound = INVALID_EDGE_WEIGHT)
|
||||
{
|
||||
forward_heap.Clear();
|
||||
reverse_heap.Clear();
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
#ifndef SHORTEST_PATH_HPP
|
||||
#define SHORTEST_PATH_HPP
|
||||
#ifndef OSRM_SHORTEST_PATH_HPP
|
||||
#define OSRM_SHORTEST_PATH_HPP
|
||||
|
||||
#include "engine/algorithm.hpp"
|
||||
#include "engine/routing_algorithms/routing_base.hpp"
|
||||
@@ -23,4 +23,4 @@ InternalRouteResult shortestPathSearch(SearchEngineData<Algorithm> &engine_worki
|
||||
} // namespace engine
|
||||
} // namespace osrm
|
||||
|
||||
#endif /* SHORTEST_PATH_HPP */
|
||||
#endif /* OSRM_SHORTEST_PATH_HPP */
|
||||
|
||||
@@ -0,0 +1,463 @@
|
||||
#ifndef OSRM_SHORTEST_PATH_IMPL_HPP
|
||||
#define OSRM_SHORTEST_PATH_IMPL_HPP
|
||||
|
||||
#include "engine/routing_algorithms/shortest_path.hpp"
|
||||
|
||||
#include <boost/assert.hpp>
|
||||
#include <boost/optional.hpp>
|
||||
|
||||
namespace osrm
|
||||
{
|
||||
namespace engine
|
||||
{
|
||||
namespace routing_algorithms
|
||||
{
|
||||
|
||||
namespace
|
||||
{
|
||||
|
||||
const static constexpr bool DO_NOT_FORCE_LOOP = false;
|
||||
|
||||
// allows a uturn at the target_phantom
|
||||
// searches source forward/reverse -> target forward/reverse
|
||||
template <typename Algorithm>
|
||||
void searchWithUTurn(SearchEngineData<Algorithm> &engine_working_data,
|
||||
const DataFacade<Algorithm> &facade,
|
||||
typename SearchEngineData<Algorithm>::QueryHeap &forward_heap,
|
||||
typename SearchEngineData<Algorithm>::QueryHeap &reverse_heap,
|
||||
const bool search_from_forward_node,
|
||||
const bool search_from_reverse_node,
|
||||
const bool search_to_forward_node,
|
||||
const bool search_to_reverse_node,
|
||||
const PhantomNode &source_phantom,
|
||||
const PhantomNode &target_phantom,
|
||||
const int total_weight_to_forward,
|
||||
const int total_weight_to_reverse,
|
||||
int &new_total_weight,
|
||||
std::vector<NodeID> &leg_packed_path)
|
||||
{
|
||||
forward_heap.Clear();
|
||||
reverse_heap.Clear();
|
||||
if (search_from_forward_node)
|
||||
{
|
||||
forward_heap.Insert(source_phantom.forward_segment_id.id,
|
||||
-source_phantom.GetForwardWeightPlusOffset(),
|
||||
source_phantom.forward_segment_id.id);
|
||||
}
|
||||
if (search_from_reverse_node)
|
||||
{
|
||||
forward_heap.Insert(source_phantom.reverse_segment_id.id,
|
||||
-source_phantom.GetReverseWeightPlusOffset(),
|
||||
source_phantom.reverse_segment_id.id);
|
||||
}
|
||||
if (search_to_forward_node)
|
||||
{
|
||||
reverse_heap.Insert(target_phantom.forward_segment_id.id,
|
||||
target_phantom.GetForwardWeightPlusOffset(),
|
||||
target_phantom.forward_segment_id.id);
|
||||
}
|
||||
if (search_to_reverse_node)
|
||||
{
|
||||
reverse_heap.Insert(target_phantom.reverse_segment_id.id,
|
||||
target_phantom.GetReverseWeightPlusOffset(),
|
||||
target_phantom.reverse_segment_id.id);
|
||||
}
|
||||
|
||||
// this is only relevent if source and target are on the same compressed edge
|
||||
auto is_oneway_source = !(search_from_forward_node && search_from_reverse_node);
|
||||
auto is_oneway_target = !(search_to_forward_node && search_to_reverse_node);
|
||||
// we only enable loops here if we can't search from forward to backward node
|
||||
auto needs_loop_forwards = is_oneway_source && needsLoopForward(source_phantom, target_phantom);
|
||||
auto needs_loop_backwards =
|
||||
is_oneway_target && needsLoopBackwards(source_phantom, target_phantom);
|
||||
|
||||
search(engine_working_data,
|
||||
facade,
|
||||
forward_heap,
|
||||
reverse_heap,
|
||||
new_total_weight,
|
||||
leg_packed_path,
|
||||
needs_loop_forwards,
|
||||
needs_loop_backwards,
|
||||
{source_phantom, target_phantom});
|
||||
|
||||
// if no route is found between two parts of the via-route, the entire route becomes
|
||||
// invalid. Adding to invalid edge weight sadly doesn't return an invalid edge weight. Here
|
||||
// we prevent the possible overflow, faking the addition of infinity + x == infinity
|
||||
if (new_total_weight != INVALID_EDGE_WEIGHT)
|
||||
new_total_weight += std::min(total_weight_to_forward, total_weight_to_reverse);
|
||||
}
|
||||
|
||||
// searches shortest path between:
|
||||
// source forward/reverse -> target forward
|
||||
// source forward/reverse -> target reverse
|
||||
template <typename Algorithm>
|
||||
void search(SearchEngineData<Algorithm> &engine_working_data,
|
||||
const DataFacade<Algorithm> &facade,
|
||||
typename SearchEngineData<Algorithm>::QueryHeap &forward_heap,
|
||||
typename SearchEngineData<Algorithm>::QueryHeap &reverse_heap,
|
||||
const bool search_from_forward_node,
|
||||
const bool search_from_reverse_node,
|
||||
const bool search_to_forward_node,
|
||||
const bool search_to_reverse_node,
|
||||
const PhantomNode &source_phantom,
|
||||
const PhantomNode &target_phantom,
|
||||
const int total_weight_to_forward,
|
||||
const int total_weight_to_reverse,
|
||||
int &new_total_weight_to_forward,
|
||||
int &new_total_weight_to_reverse,
|
||||
std::vector<NodeID> &leg_packed_path_forward,
|
||||
std::vector<NodeID> &leg_packed_path_reverse)
|
||||
{
|
||||
if (search_to_forward_node)
|
||||
{
|
||||
forward_heap.Clear();
|
||||
reverse_heap.Clear();
|
||||
reverse_heap.Insert(target_phantom.forward_segment_id.id,
|
||||
target_phantom.GetForwardWeightPlusOffset(),
|
||||
target_phantom.forward_segment_id.id);
|
||||
|
||||
if (search_from_forward_node)
|
||||
{
|
||||
forward_heap.Insert(source_phantom.forward_segment_id.id,
|
||||
total_weight_to_forward -
|
||||
source_phantom.GetForwardWeightPlusOffset(),
|
||||
source_phantom.forward_segment_id.id);
|
||||
}
|
||||
if (search_from_reverse_node)
|
||||
{
|
||||
forward_heap.Insert(source_phantom.reverse_segment_id.id,
|
||||
total_weight_to_reverse -
|
||||
source_phantom.GetReverseWeightPlusOffset(),
|
||||
source_phantom.reverse_segment_id.id);
|
||||
}
|
||||
|
||||
search(engine_working_data,
|
||||
facade,
|
||||
forward_heap,
|
||||
reverse_heap,
|
||||
new_total_weight_to_forward,
|
||||
leg_packed_path_forward,
|
||||
needsLoopForward(source_phantom, target_phantom),
|
||||
routing_algorithms::DO_NOT_FORCE_LOOP,
|
||||
{source_phantom, target_phantom});
|
||||
}
|
||||
|
||||
if (search_to_reverse_node)
|
||||
{
|
||||
forward_heap.Clear();
|
||||
reverse_heap.Clear();
|
||||
reverse_heap.Insert(target_phantom.reverse_segment_id.id,
|
||||
target_phantom.GetReverseWeightPlusOffset(),
|
||||
target_phantom.reverse_segment_id.id);
|
||||
if (search_from_forward_node)
|
||||
{
|
||||
forward_heap.Insert(source_phantom.forward_segment_id.id,
|
||||
total_weight_to_forward -
|
||||
source_phantom.GetForwardWeightPlusOffset(),
|
||||
source_phantom.forward_segment_id.id);
|
||||
}
|
||||
if (search_from_reverse_node)
|
||||
{
|
||||
forward_heap.Insert(source_phantom.reverse_segment_id.id,
|
||||
total_weight_to_reverse -
|
||||
source_phantom.GetReverseWeightPlusOffset(),
|
||||
source_phantom.reverse_segment_id.id);
|
||||
}
|
||||
|
||||
search(engine_working_data,
|
||||
facade,
|
||||
forward_heap,
|
||||
reverse_heap,
|
||||
new_total_weight_to_reverse,
|
||||
leg_packed_path_reverse,
|
||||
routing_algorithms::DO_NOT_FORCE_LOOP,
|
||||
needsLoopBackwards(source_phantom, target_phantom),
|
||||
{source_phantom, target_phantom});
|
||||
}
|
||||
}
|
||||
|
||||
template <typename Algorithm>
|
||||
void unpackLegs(const DataFacade<Algorithm> &facade,
|
||||
const std::vector<PhantomNodes> &phantom_nodes_vector,
|
||||
const std::vector<NodeID> &total_packed_path,
|
||||
const std::vector<std::size_t> &packed_leg_begin,
|
||||
const EdgeWeight shortest_path_weight,
|
||||
InternalRouteResult &raw_route_data)
|
||||
{
|
||||
raw_route_data.unpacked_path_segments.resize(packed_leg_begin.size() - 1);
|
||||
|
||||
raw_route_data.shortest_path_weight = shortest_path_weight;
|
||||
|
||||
for (const auto current_leg : util::irange<std::size_t>(0UL, packed_leg_begin.size() - 1))
|
||||
{
|
||||
auto leg_begin = total_packed_path.begin() + packed_leg_begin[current_leg];
|
||||
auto leg_end = total_packed_path.begin() + packed_leg_begin[current_leg + 1];
|
||||
const auto &unpack_phantom_node_pair = phantom_nodes_vector[current_leg];
|
||||
unpackPath(facade,
|
||||
leg_begin,
|
||||
leg_end,
|
||||
unpack_phantom_node_pair,
|
||||
raw_route_data.unpacked_path_segments[current_leg]);
|
||||
|
||||
raw_route_data.source_traversed_in_reverse.push_back(
|
||||
(*leg_begin != phantom_nodes_vector[current_leg].source_phantom.forward_segment_id.id));
|
||||
raw_route_data.target_traversed_in_reverse.push_back(
|
||||
(*std::prev(leg_end) !=
|
||||
phantom_nodes_vector[current_leg].target_phantom.forward_segment_id.id));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
template <typename Algorithm>
|
||||
InternalRouteResult shortestPathSearch(SearchEngineData<Algorithm> &engine_working_data,
|
||||
const DataFacade<Algorithm> &facade,
|
||||
const std::vector<PhantomNodes> &phantom_nodes_vector,
|
||||
const boost::optional<bool> continue_straight_at_waypoint)
|
||||
{
|
||||
InternalRouteResult raw_route_data;
|
||||
raw_route_data.segment_end_coordinates = phantom_nodes_vector;
|
||||
const bool allow_uturn_at_waypoint =
|
||||
!(continue_straight_at_waypoint ? *continue_straight_at_waypoint
|
||||
: facade.GetContinueStraightDefault());
|
||||
|
||||
engine_working_data.InitializeOrClearFirstThreadLocalStorage(facade.GetNumberOfNodes());
|
||||
|
||||
auto &forward_heap = *engine_working_data.forward_heap_1;
|
||||
auto &reverse_heap = *engine_working_data.reverse_heap_1;
|
||||
|
||||
int total_weight_to_forward = 0;
|
||||
int total_weight_to_reverse = 0;
|
||||
bool search_from_forward_node =
|
||||
phantom_nodes_vector.front().source_phantom.IsValidForwardSource();
|
||||
bool search_from_reverse_node =
|
||||
phantom_nodes_vector.front().source_phantom.IsValidReverseSource();
|
||||
|
||||
std::vector<NodeID> prev_packed_leg_to_forward;
|
||||
std::vector<NodeID> prev_packed_leg_to_reverse;
|
||||
|
||||
std::vector<NodeID> total_packed_path_to_forward;
|
||||
std::vector<std::size_t> packed_leg_to_forward_begin;
|
||||
std::vector<NodeID> total_packed_path_to_reverse;
|
||||
std::vector<std::size_t> packed_leg_to_reverse_begin;
|
||||
|
||||
std::size_t current_leg = 0;
|
||||
// this implements a dynamic program that finds the shortest route through
|
||||
// a list of vias
|
||||
for (const auto &phantom_node_pair : phantom_nodes_vector)
|
||||
{
|
||||
int new_total_weight_to_forward = INVALID_EDGE_WEIGHT;
|
||||
int new_total_weight_to_reverse = INVALID_EDGE_WEIGHT;
|
||||
|
||||
std::vector<NodeID> packed_leg_to_forward;
|
||||
std::vector<NodeID> packed_leg_to_reverse;
|
||||
|
||||
const auto &source_phantom = phantom_node_pair.source_phantom;
|
||||
const auto &target_phantom = phantom_node_pair.target_phantom;
|
||||
|
||||
bool search_to_forward_node = target_phantom.IsValidForwardTarget();
|
||||
bool search_to_reverse_node = target_phantom.IsValidReverseTarget();
|
||||
|
||||
BOOST_ASSERT(!search_from_forward_node || source_phantom.IsValidForwardSource());
|
||||
BOOST_ASSERT(!search_from_reverse_node || source_phantom.IsValidReverseSource());
|
||||
|
||||
if (search_to_reverse_node || search_to_forward_node)
|
||||
{
|
||||
if (allow_uturn_at_waypoint)
|
||||
{
|
||||
searchWithUTurn(engine_working_data,
|
||||
facade,
|
||||
forward_heap,
|
||||
reverse_heap,
|
||||
search_from_forward_node,
|
||||
search_from_reverse_node,
|
||||
search_to_forward_node,
|
||||
search_to_reverse_node,
|
||||
source_phantom,
|
||||
target_phantom,
|
||||
total_weight_to_forward,
|
||||
total_weight_to_reverse,
|
||||
new_total_weight_to_forward,
|
||||
packed_leg_to_forward);
|
||||
// if only the reverse node is valid (e.g. when using the match plugin) we
|
||||
// actually need to move
|
||||
if (!target_phantom.IsValidForwardTarget())
|
||||
{
|
||||
BOOST_ASSERT(target_phantom.IsValidReverseTarget());
|
||||
new_total_weight_to_reverse = new_total_weight_to_forward;
|
||||
packed_leg_to_reverse = std::move(packed_leg_to_forward);
|
||||
new_total_weight_to_forward = INVALID_EDGE_WEIGHT;
|
||||
|
||||
// (*)
|
||||
//
|
||||
// Below we have to check if new_total_weight_to_forward is invalid.
|
||||
// This prevents use-after-move on packed_leg_to_forward.
|
||||
}
|
||||
else if (target_phantom.IsValidReverseTarget())
|
||||
{
|
||||
new_total_weight_to_reverse = new_total_weight_to_forward;
|
||||
packed_leg_to_reverse = packed_leg_to_forward;
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
search(engine_working_data,
|
||||
facade,
|
||||
forward_heap,
|
||||
reverse_heap,
|
||||
search_from_forward_node,
|
||||
search_from_reverse_node,
|
||||
search_to_forward_node,
|
||||
search_to_reverse_node,
|
||||
source_phantom,
|
||||
target_phantom,
|
||||
total_weight_to_forward,
|
||||
total_weight_to_reverse,
|
||||
new_total_weight_to_forward,
|
||||
new_total_weight_to_reverse,
|
||||
packed_leg_to_forward,
|
||||
packed_leg_to_reverse);
|
||||
}
|
||||
}
|
||||
|
||||
// Note: To make sure we do not access the moved-from packed_leg_to_forward
|
||||
// we guard its access by a check for invalid edge weight. See (*) above.
|
||||
|
||||
// No path found for both target nodes?
|
||||
if ((INVALID_EDGE_WEIGHT == new_total_weight_to_forward) &&
|
||||
(INVALID_EDGE_WEIGHT == new_total_weight_to_reverse))
|
||||
{
|
||||
return raw_route_data;
|
||||
}
|
||||
|
||||
// we need to figure out how the new legs connect to the previous ones
|
||||
if (current_leg > 0)
|
||||
{
|
||||
bool forward_to_forward =
|
||||
(new_total_weight_to_forward != INVALID_EDGE_WEIGHT) &&
|
||||
packed_leg_to_forward.front() == source_phantom.forward_segment_id.id;
|
||||
bool reverse_to_forward =
|
||||
(new_total_weight_to_forward != INVALID_EDGE_WEIGHT) &&
|
||||
packed_leg_to_forward.front() == source_phantom.reverse_segment_id.id;
|
||||
bool forward_to_reverse =
|
||||
(new_total_weight_to_reverse != INVALID_EDGE_WEIGHT) &&
|
||||
packed_leg_to_reverse.front() == source_phantom.forward_segment_id.id;
|
||||
bool reverse_to_reverse =
|
||||
(new_total_weight_to_reverse != INVALID_EDGE_WEIGHT) &&
|
||||
packed_leg_to_reverse.front() == source_phantom.reverse_segment_id.id;
|
||||
|
||||
BOOST_ASSERT(!forward_to_forward || !reverse_to_forward);
|
||||
BOOST_ASSERT(!forward_to_reverse || !reverse_to_reverse);
|
||||
|
||||
// in this case we always need to copy
|
||||
if (forward_to_forward && forward_to_reverse)
|
||||
{
|
||||
// in this case we copy the path leading to the source forward node
|
||||
// and change the case
|
||||
total_packed_path_to_reverse = total_packed_path_to_forward;
|
||||
packed_leg_to_reverse_begin = packed_leg_to_forward_begin;
|
||||
forward_to_reverse = false;
|
||||
reverse_to_reverse = true;
|
||||
}
|
||||
else if (reverse_to_forward && reverse_to_reverse)
|
||||
{
|
||||
total_packed_path_to_forward = total_packed_path_to_reverse;
|
||||
packed_leg_to_forward_begin = packed_leg_to_reverse_begin;
|
||||
reverse_to_forward = false;
|
||||
forward_to_forward = true;
|
||||
}
|
||||
BOOST_ASSERT(!forward_to_forward || !forward_to_reverse);
|
||||
BOOST_ASSERT(!reverse_to_forward || !reverse_to_reverse);
|
||||
|
||||
// in this case we just need to swap to regain the correct mapping
|
||||
if (reverse_to_forward || forward_to_reverse)
|
||||
{
|
||||
total_packed_path_to_forward.swap(total_packed_path_to_reverse);
|
||||
packed_leg_to_forward_begin.swap(packed_leg_to_reverse_begin);
|
||||
}
|
||||
}
|
||||
|
||||
if (new_total_weight_to_forward != INVALID_EDGE_WEIGHT)
|
||||
{
|
||||
BOOST_ASSERT(target_phantom.IsValidForwardTarget());
|
||||
|
||||
packed_leg_to_forward_begin.push_back(total_packed_path_to_forward.size());
|
||||
total_packed_path_to_forward.insert(total_packed_path_to_forward.end(),
|
||||
packed_leg_to_forward.begin(),
|
||||
packed_leg_to_forward.end());
|
||||
search_from_forward_node = true;
|
||||
}
|
||||
else
|
||||
{
|
||||
total_packed_path_to_forward.clear();
|
||||
packed_leg_to_forward_begin.clear();
|
||||
search_from_forward_node = false;
|
||||
}
|
||||
|
||||
if (new_total_weight_to_reverse != INVALID_EDGE_WEIGHT)
|
||||
{
|
||||
BOOST_ASSERT(target_phantom.IsValidReverseTarget());
|
||||
|
||||
packed_leg_to_reverse_begin.push_back(total_packed_path_to_reverse.size());
|
||||
total_packed_path_to_reverse.insert(total_packed_path_to_reverse.end(),
|
||||
packed_leg_to_reverse.begin(),
|
||||
packed_leg_to_reverse.end());
|
||||
search_from_reverse_node = true;
|
||||
}
|
||||
else
|
||||
{
|
||||
total_packed_path_to_reverse.clear();
|
||||
packed_leg_to_reverse_begin.clear();
|
||||
search_from_reverse_node = false;
|
||||
}
|
||||
|
||||
prev_packed_leg_to_forward = std::move(packed_leg_to_forward);
|
||||
prev_packed_leg_to_reverse = std::move(packed_leg_to_reverse);
|
||||
|
||||
total_weight_to_forward = new_total_weight_to_forward;
|
||||
total_weight_to_reverse = new_total_weight_to_reverse;
|
||||
|
||||
++current_leg;
|
||||
}
|
||||
|
||||
BOOST_ASSERT(total_weight_to_forward != INVALID_EDGE_WEIGHT ||
|
||||
total_weight_to_reverse != INVALID_EDGE_WEIGHT);
|
||||
|
||||
// We make sure the fastest route is always in packed_legs_to_forward
|
||||
if (total_weight_to_forward < total_weight_to_reverse ||
|
||||
(total_weight_to_forward == total_weight_to_reverse &&
|
||||
total_packed_path_to_forward.size() < total_packed_path_to_reverse.size()))
|
||||
{
|
||||
// insert sentinel
|
||||
packed_leg_to_forward_begin.push_back(total_packed_path_to_forward.size());
|
||||
BOOST_ASSERT(packed_leg_to_forward_begin.size() == phantom_nodes_vector.size() + 1);
|
||||
|
||||
unpackLegs(facade,
|
||||
phantom_nodes_vector,
|
||||
total_packed_path_to_forward,
|
||||
packed_leg_to_forward_begin,
|
||||
total_weight_to_forward,
|
||||
raw_route_data);
|
||||
}
|
||||
else
|
||||
{
|
||||
// insert sentinel
|
||||
packed_leg_to_reverse_begin.push_back(total_packed_path_to_reverse.size());
|
||||
BOOST_ASSERT(packed_leg_to_reverse_begin.size() == phantom_nodes_vector.size() + 1);
|
||||
|
||||
unpackLegs(facade,
|
||||
phantom_nodes_vector,
|
||||
total_packed_path_to_reverse,
|
||||
packed_leg_to_reverse_begin,
|
||||
total_weight_to_reverse,
|
||||
raw_route_data);
|
||||
}
|
||||
|
||||
return raw_route_data;
|
||||
}
|
||||
|
||||
} // namespace routing_algorithms
|
||||
} // namespace engine
|
||||
} // namespace osrm
|
||||
|
||||
#endif /* OSRM_SHORTEST_PATH_IMPL_HPP */
|
||||
@@ -3,7 +3,6 @@
|
||||
|
||||
#include "engine/algorithm.hpp"
|
||||
#include "engine/datafacade.hpp"
|
||||
#include "engine/datafacade/datafacade_base.hpp"
|
||||
|
||||
#include "util/coordinate.hpp"
|
||||
#include "util/typedefs.hpp"
|
||||
|
||||
@@ -1,12 +1,12 @@
|
||||
#ifndef SEARCH_ENGINE_DATA_HPP
|
||||
#define SEARCH_ENGINE_DATA_HPP
|
||||
|
||||
#include <boost/thread/tss.hpp>
|
||||
|
||||
#include "engine/algorithm.hpp"
|
||||
#include "util/query_heap.hpp"
|
||||
#include "util/typedefs.hpp"
|
||||
|
||||
#include <boost/thread/tss.hpp>
|
||||
|
||||
namespace osrm
|
||||
{
|
||||
namespace engine
|
||||
@@ -37,7 +37,6 @@ template <> struct SearchEngineData<routing_algorithms::ch::Algorithm>
|
||||
{
|
||||
using QueryHeap = util::
|
||||
QueryHeap<NodeID, NodeID, EdgeWeight, HeapData, util::UnorderedMapStorage<NodeID, int>>;
|
||||
using SearchEngineHeapPtr = boost::thread_specific_ptr<QueryHeap>;
|
||||
|
||||
using ManyToManyQueryHeap = util::QueryHeap<NodeID,
|
||||
NodeID,
|
||||
@@ -45,6 +44,7 @@ template <> struct SearchEngineData<routing_algorithms::ch::Algorithm>
|
||||
ManyToManyHeapData,
|
||||
util::UnorderedMapStorage<NodeID, int>>;
|
||||
|
||||
using SearchEngineHeapPtr = boost::thread_specific_ptr<QueryHeap>;
|
||||
using ManyToManyHeapPtr = boost::thread_specific_ptr<ManyToManyQueryHeap>;
|
||||
|
||||
static SearchEngineHeapPtr forward_heap_1;
|
||||
@@ -106,7 +106,6 @@ template <> struct SearchEngineData<routing_algorithms::mld::Algorithm>
|
||||
util::UnorderedMapStorage<NodeID, int>>;
|
||||
|
||||
using SearchEngineHeapPtr = boost::thread_specific_ptr<QueryHeap>;
|
||||
|
||||
using ManyToManyHeapPtr = boost::thread_specific_ptr<ManyToManyQueryHeap>;
|
||||
|
||||
static SearchEngineHeapPtr forward_heap_1;
|
||||
|
||||
@@ -10,6 +10,8 @@
|
||||
#include <string>
|
||||
#include <vector>
|
||||
|
||||
#include <boost/optional.hpp>
|
||||
|
||||
namespace osrm
|
||||
{
|
||||
namespace extractor
|
||||
@@ -36,7 +38,11 @@ class CompressedEdgeContainer
|
||||
const EdgeWeight weight1,
|
||||
const EdgeWeight weight2,
|
||||
const EdgeDuration duration1,
|
||||
const EdgeDuration duration2);
|
||||
const EdgeDuration duration2,
|
||||
// node-penalties can be added before/or after the traversal of an edge which
|
||||
// depends on whether we traverse the link forwards or backwards.
|
||||
const boost::optional<EdgeWeight> node_weight_penalty = boost::none,
|
||||
const boost::optional<EdgeDuration> node_duration_penalty = boost::none);
|
||||
|
||||
void AddUncompressedEdge(const EdgeID edge_id,
|
||||
const NodeID target_node,
|
||||
|
||||
@@ -0,0 +1,28 @@
|
||||
#ifndef OSRM_EXTRACTOR_CONDITIONAL_TURN_PENALTY_HPP_
|
||||
#define OSRM_EXTRACTOR_CONDITIONAL_TURN_PENALTY_HPP_
|
||||
|
||||
#include "util/coordinate.hpp"
|
||||
#include "util/opening_hours.hpp"
|
||||
#include <cstdint>
|
||||
#include <vector>
|
||||
|
||||
#include <type_traits>
|
||||
|
||||
namespace osrm
|
||||
|
||||
{
|
||||
namespace extractor
|
||||
{
|
||||
|
||||
struct ConditionalTurnPenalty
|
||||
{
|
||||
// offset into the sequential list of turn penalties (see TurnIndexBlock for reference);
|
||||
std::uint64_t turn_offset;
|
||||
util::Coordinate location;
|
||||
std::vector<util::OpeningHours> conditions;
|
||||
};
|
||||
|
||||
} // namespace extractor
|
||||
} // namespace osrm
|
||||
|
||||
#endif // OSRM_EXTRACTOR_CONDITIONAL_TURN_PENALTY_HPP_
|
||||
@@ -4,6 +4,7 @@
|
||||
#define EDGE_BASED_GRAPH_FACTORY_HPP_
|
||||
|
||||
#include "extractor/compressed_edge_container.hpp"
|
||||
#include "extractor/conditional_turn_penalty.hpp"
|
||||
#include "extractor/edge_based_edge.hpp"
|
||||
#include "extractor/edge_based_node_segment.hpp"
|
||||
#include "extractor/extraction_turn.hpp"
|
||||
@@ -16,7 +17,7 @@
|
||||
#include "extractor/packed_osm_ids.hpp"
|
||||
#include "extractor/profile_properties.hpp"
|
||||
#include "extractor/query_node.hpp"
|
||||
#include "extractor/restriction_map.hpp"
|
||||
#include "extractor/restriction_index.hpp"
|
||||
#include "extractor/way_restriction_map.hpp"
|
||||
|
||||
#include "util/concurrent_id_map.hpp"
|
||||
@@ -41,11 +42,6 @@
|
||||
#include <unordered_set>
|
||||
#include <vector>
|
||||
|
||||
#include <boost/filesystem/fstream.hpp>
|
||||
|
||||
#include <tbb/concurrent_unordered_map.h>
|
||||
#include <tbb/concurrent_vector.h>
|
||||
|
||||
namespace osrm
|
||||
{
|
||||
namespace extractor
|
||||
@@ -92,7 +88,9 @@ class EdgeBasedGraphFactory
|
||||
const std::string &turn_duration_penalties_filename,
|
||||
const std::string &turn_penalties_index_filename,
|
||||
const std::string &cnbg_ebg_mapping_path,
|
||||
const std::string &conditional_penalties_filename,
|
||||
const RestrictionMap &node_restriction_map,
|
||||
const ConditionalRestrictionMap &conditional_restriction_map,
|
||||
const WayRestrictionMap &way_restriction_map);
|
||||
|
||||
// The following get access functions destroy the content in the factory
|
||||
@@ -124,6 +122,18 @@ class EdgeBasedGraphFactory
|
||||
private:
|
||||
using EdgeData = util::NodeBasedDynamicGraph::EdgeData;
|
||||
|
||||
struct Conditional
|
||||
{
|
||||
// the edge based nodes allow for a unique identification of conditionals
|
||||
NodeID from_node;
|
||||
NodeID to_node;
|
||||
ConditionalTurnPenalty penalty;
|
||||
};
|
||||
|
||||
// assign the correct index to the penalty value stored in the conditional
|
||||
std::vector<ConditionalTurnPenalty>
|
||||
IndexConditionals(std::vector<Conditional> &&conditionals) const;
|
||||
|
||||
//! maps index from m_edge_based_node_list to ture/false if the node is an entry point to the
|
||||
//! graph
|
||||
std::vector<bool> m_edge_based_node_is_startpoint;
|
||||
@@ -173,7 +183,9 @@ class EdgeBasedGraphFactory
|
||||
const std::string &turn_weight_penalties_filename,
|
||||
const std::string &turn_duration_penalties_filename,
|
||||
const std::string &turn_penalties_index_filename,
|
||||
const std::string &conditional_turn_penalties_filename,
|
||||
const RestrictionMap &node_restriction_map,
|
||||
const ConditionalRestrictionMap &conditional_restriction_map,
|
||||
const WayRestrictionMap &way_restriction_map);
|
||||
|
||||
NBGToEBG InsertEdgeBasedNode(const NodeID u, const NodeID v);
|
||||
|
||||
@@ -27,7 +27,6 @@ class ExtractionContainers
|
||||
void PrepareEdges(ScriptingEnvironment &scripting_environment);
|
||||
|
||||
void WriteNodes(storage::io::FileWriter &file_out) const;
|
||||
void WriteConditionalRestrictions(const std::string &restrictions_file_name);
|
||||
void WriteEdges(storage::io::FileWriter &file_out) const;
|
||||
void WriteCharData(const std::string &file_name);
|
||||
|
||||
@@ -40,7 +39,7 @@ class ExtractionContainers
|
||||
using NameOffsets = std::vector<unsigned>;
|
||||
|
||||
std::vector<OSMNodeID> barrier_nodes;
|
||||
std::vector<OSMNodeID> traffic_lights;
|
||||
std::vector<OSMNodeID> traffic_signals;
|
||||
NodeIDVector used_node_id_list;
|
||||
NodeVector all_nodes_list;
|
||||
EdgeVector all_edges_list;
|
||||
@@ -65,7 +64,6 @@ class ExtractionContainers
|
||||
|
||||
void PrepareData(ScriptingEnvironment &scripting_environment,
|
||||
const std::string &osrm_path,
|
||||
const std::string &restrictions_file_name,
|
||||
const std::string &names_data_path);
|
||||
};
|
||||
}
|
||||
|
||||
@@ -22,6 +22,14 @@ struct ExtractionTurn
|
||||
{
|
||||
}
|
||||
|
||||
ExtractionTurn(const bool has_traffic_light = false)
|
||||
: angle(0), turn_type(guidance::TurnType::NoTurn),
|
||||
direction_modifier(guidance::DirectionModifier::Straight),
|
||||
has_traffic_light(has_traffic_light), weight(0.), duration(0.), source_restricted(false),
|
||||
target_restricted(false)
|
||||
{
|
||||
}
|
||||
|
||||
const double angle;
|
||||
const guidance::TurnType::Enum turn_type;
|
||||
const guidance::DirectionModifier::Enum direction_modifier;
|
||||
|
||||
@@ -56,7 +56,9 @@ class Extractor
|
||||
private:
|
||||
ExtractorConfig config;
|
||||
|
||||
std::tuple<guidance::LaneDescriptionMap, std::vector<TurnRestriction>>
|
||||
std::tuple<guidance::LaneDescriptionMap,
|
||||
std::vector<TurnRestriction>,
|
||||
std::vector<ConditionalTurnRestriction>>
|
||||
ParseOSMData(ScriptingEnvironment &scripting_environment, const unsigned number_of_threads);
|
||||
|
||||
std::pair<std::size_t, EdgeID>
|
||||
@@ -70,6 +72,7 @@ class Extractor
|
||||
util::DeallocatingVector<EdgeBasedEdge> &edge_based_edge_list,
|
||||
const std::string &intersection_class_output_file,
|
||||
std::vector<TurnRestriction> &turn_restrictions,
|
||||
std::vector<ConditionalTurnRestriction> &conditional_turn_restrictions,
|
||||
guidance::LaneDescriptionMap &turn_lane_map);
|
||||
void FindComponents(unsigned max_edge_id,
|
||||
const util::DeallocatingVector<EdgeBasedEdge> &input_edge_list,
|
||||
@@ -89,6 +92,10 @@ class Extractor
|
||||
static void WriteCompressedNodeBasedGraph(const std::string &path,
|
||||
const util::NodeBasedDynamicGraph &graph,
|
||||
const std::vector<util::Coordinate> &coordiantes);
|
||||
|
||||
void WriteConditionalRestrictions(
|
||||
const std::string &path,
|
||||
std::vector<ConditionalTurnRestriction> &conditional_turn_restrictions);
|
||||
};
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,6 +1,7 @@
|
||||
#ifndef GEOMETRY_COMPRESSOR_HPP
|
||||
#define GEOMETRY_COMPRESSOR_HPP
|
||||
|
||||
#include "extractor/scripting_environment.hpp"
|
||||
#include "util/typedefs.hpp"
|
||||
|
||||
#include "util/node_based_graph.hpp"
|
||||
@@ -24,7 +25,9 @@ class GraphCompressor
|
||||
public:
|
||||
void Compress(const std::unordered_set<NodeID> &barrier_nodes,
|
||||
const std::unordered_set<NodeID> &traffic_lights,
|
||||
ScriptingEnvironment &scripting_environment,
|
||||
std::vector<TurnRestriction> &turn_restrictions,
|
||||
std::vector<ConditionalTurnRestriction> &conditional_turn_restrictions,
|
||||
util::NodeBasedDynamicGraph &graph,
|
||||
CompressedEdgeContainer &geometry_compressor);
|
||||
|
||||
|
||||
@@ -6,7 +6,7 @@
|
||||
#include "extractor/guidance/intersection.hpp"
|
||||
#include "extractor/guidance/intersection_normalization_operation.hpp"
|
||||
#include "extractor/query_node.hpp"
|
||||
#include "extractor/restriction_map.hpp"
|
||||
#include "extractor/restriction_index.hpp"
|
||||
#include "util/attributes.hpp"
|
||||
#include "util/node_based_graph.hpp"
|
||||
#include "util/typedefs.hpp"
|
||||
@@ -116,14 +116,6 @@ class IntersectionGenerator
|
||||
|
||||
// own state, used to find the correct coordinates along a road
|
||||
const CoordinateExtractor coordinate_extractor;
|
||||
|
||||
// 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;
|
||||
};
|
||||
|
||||
} // namespace guidance
|
||||
|
||||
@@ -14,7 +14,7 @@
|
||||
#include "extractor/guidance/turn_classification.hpp"
|
||||
#include "extractor/guidance/turn_handler.hpp"
|
||||
#include "extractor/query_node.hpp"
|
||||
#include "extractor/restriction_map.hpp"
|
||||
#include "extractor/restriction_index.hpp"
|
||||
#include "extractor/suffix_table.hpp"
|
||||
|
||||
#include "util/attributes.hpp"
|
||||
|
||||
@@ -83,7 +83,8 @@ struct ProfileProperties
|
||||
std::string GetClassName(std::size_t index) const
|
||||
{
|
||||
BOOST_ASSERT(index <= MAX_CLASS_INDEX);
|
||||
return std::string(class_names[index]);
|
||||
const auto &name_it = std::begin(class_names) + index;
|
||||
return std::string(*name_it);
|
||||
}
|
||||
|
||||
double GetWeightMultiplier() const { return std::pow(10., weight_precision); }
|
||||
|
||||
@@ -1,6 +1,7 @@
|
||||
#ifndef OSRM_EXTRACTOR_RESTRICTION_COMPRESSOR_HPP_
|
||||
#define OSRM_EXTRACTOR_RESTRICTION_COMPRESSOR_HPP_
|
||||
|
||||
#include "extractor/restriction.hpp"
|
||||
#include "util/typedefs.hpp"
|
||||
|
||||
#include <boost/unordered_map.hpp>
|
||||
@@ -26,7 +27,8 @@ struct TurnRestriction;
|
||||
class RestrictionCompressor
|
||||
{
|
||||
public:
|
||||
RestrictionCompressor(std::vector<TurnRestriction> &restrictions);
|
||||
RestrictionCompressor(std::vector<TurnRestriction> &restrictions,
|
||||
std::vector<ConditionalTurnRestriction> &conditional_turn_restrictions);
|
||||
|
||||
// account for the compression of `from-via-to` into `from-to`
|
||||
void Compress(const NodeID from, const NodeID via, const NodeID to);
|
||||
|
||||
@@ -14,8 +14,9 @@ namespace extractor
|
||||
// To avoid handling invalid restrictions / creating unnecessary duplicate nodes for via-ways, we do
|
||||
// a pre-flight check for restrictions and remove all invalid restrictions from the data. Use as
|
||||
// `restrictions = removeInvalidRestrictions(std::move(restrictions))`
|
||||
std::vector<TurnRestriction> removeInvalidRestrictions(std::vector<TurnRestriction>,
|
||||
const util::NodeBasedDynamicGraph &);
|
||||
std::vector<ConditionalTurnRestriction>
|
||||
removeInvalidRestrictions(std::vector<ConditionalTurnRestriction>,
|
||||
const util::NodeBasedDynamicGraph &);
|
||||
|
||||
} // namespace extractor
|
||||
} // namespace osrm
|
||||
|
||||
@@ -0,0 +1,101 @@
|
||||
#ifndef OSRM_EXTRACTOR_RESTRICTION_INDEX_HPP_
|
||||
#define OSRM_EXTRACTOR_RESTRICTION_INDEX_HPP_
|
||||
|
||||
#include "extractor/restriction.hpp"
|
||||
#include "util/typedefs.hpp"
|
||||
|
||||
#include <boost/unordered_map.hpp>
|
||||
|
||||
#include <utility>
|
||||
#include <vector>
|
||||
|
||||
namespace osrm
|
||||
{
|
||||
namespace extractor
|
||||
{
|
||||
|
||||
// allows easy check for whether a node intersection is present at a given intersection
|
||||
template <typename restriction_type> class RestrictionIndex
|
||||
{
|
||||
public:
|
||||
using value_type = restriction_type;
|
||||
|
||||
template <typename extractor_type>
|
||||
RestrictionIndex(std::vector<restriction_type> &restrictions, extractor_type extractor);
|
||||
|
||||
bool IsIndexed(NodeID first, NodeID second) const;
|
||||
|
||||
auto Restrictions(NodeID first, NodeID second) const
|
||||
{
|
||||
return restriction_hash.equal_range(std::make_pair(first, second));
|
||||
};
|
||||
|
||||
auto Size() const { return restriction_hash.size(); }
|
||||
|
||||
private:
|
||||
boost::unordered_multimap<std::pair<NodeID, NodeID>, restriction_type *> restriction_hash;
|
||||
};
|
||||
|
||||
template <typename restriction_type>
|
||||
template <typename extractor_type>
|
||||
RestrictionIndex<restriction_type>::RestrictionIndex(std::vector<restriction_type> &restrictions,
|
||||
extractor_type extractor)
|
||||
{
|
||||
// build a multi-map
|
||||
for (auto &restriction : restrictions)
|
||||
restriction_hash.insert(std::make_pair(extractor(restriction), &restriction));
|
||||
}
|
||||
|
||||
template <typename restriction_type>
|
||||
bool RestrictionIndex<restriction_type>::IsIndexed(const NodeID first, const NodeID second) const
|
||||
{
|
||||
return restriction_hash.count(std::make_pair(first, second));
|
||||
}
|
||||
|
||||
struct IndexNodeByFromAndVia
|
||||
{
|
||||
std::pair<NodeID, NodeID> operator()(const TurnRestriction &restriction)
|
||||
{
|
||||
const auto &node = restriction.AsNodeRestriction();
|
||||
return std::make_pair(node.from, node.via);
|
||||
};
|
||||
};
|
||||
|
||||
// check wheter a turn is restricted within a restriction_index
|
||||
template <typename restriction_map_type>
|
||||
std::pair<bool, typename restriction_map_type::value_type *>
|
||||
isRestricted(const NodeID from,
|
||||
const NodeID via,
|
||||
const NodeID to,
|
||||
const restriction_map_type &restriction_map)
|
||||
{
|
||||
const auto range = restriction_map.Restrictions(from, via);
|
||||
|
||||
// check if a given node_restriction is targeting node
|
||||
const auto to_is_restricted = [to](const auto &pair) {
|
||||
const auto &restriction = *pair.second;
|
||||
if (restriction.Type() == RestrictionType::NODE_RESTRICTION)
|
||||
{
|
||||
auto const &as_node = restriction.AsNodeRestriction();
|
||||
auto const restricted = restriction.is_only ? (to != as_node.to) : (to == as_node.to);
|
||||
|
||||
return restricted;
|
||||
}
|
||||
return false;
|
||||
};
|
||||
|
||||
auto itr = std::find_if(range.first, range.second, to_is_restricted);
|
||||
|
||||
if (itr != range.second)
|
||||
return {true, itr->second};
|
||||
else
|
||||
return {false, NULL};
|
||||
}
|
||||
|
||||
using RestrictionMap = RestrictionIndex<TurnRestriction>;
|
||||
using ConditionalRestrictionMap = RestrictionIndex<ConditionalTurnRestriction>;
|
||||
|
||||
} // namespace extractor
|
||||
} // namespace osrm
|
||||
|
||||
#endif // OSRM_EXTRACTOR_RESTRICTION_INDEX_HPP_
|
||||
@@ -1,110 +0,0 @@
|
||||
#ifndef RESTRICTION_MAP_HPP
|
||||
#define RESTRICTION_MAP_HPP
|
||||
|
||||
#include "extractor/edge_based_edge.hpp"
|
||||
#include "extractor/restriction.hpp"
|
||||
#include "util/std_hash.hpp"
|
||||
#include "util/typedefs.hpp"
|
||||
|
||||
#include <boost/assert.hpp>
|
||||
|
||||
#include <memory>
|
||||
#include <unordered_map>
|
||||
#include <unordered_set>
|
||||
#include <vector>
|
||||
|
||||
namespace osrm
|
||||
{
|
||||
namespace extractor
|
||||
{
|
||||
|
||||
struct RestrictionSource
|
||||
{
|
||||
NodeID start_node;
|
||||
NodeID via_node;
|
||||
|
||||
RestrictionSource(NodeID start, NodeID via) : start_node(start), via_node(via) {}
|
||||
|
||||
friend inline bool operator==(const RestrictionSource &lhs, const RestrictionSource &rhs)
|
||||
{
|
||||
return (lhs.start_node == rhs.start_node && lhs.via_node == rhs.via_node);
|
||||
}
|
||||
};
|
||||
|
||||
struct RestrictionTarget
|
||||
{
|
||||
NodeID target_node;
|
||||
bool is_only;
|
||||
|
||||
explicit RestrictionTarget(NodeID target, bool only) : target_node(target), is_only(only) {}
|
||||
|
||||
friend inline bool operator==(const RestrictionTarget &lhs, const RestrictionTarget &rhs)
|
||||
{
|
||||
return (lhs.target_node == rhs.target_node && lhs.is_only == rhs.is_only);
|
||||
}
|
||||
};
|
||||
}
|
||||
}
|
||||
|
||||
namespace std
|
||||
{
|
||||
template <> struct hash<osrm::extractor::RestrictionSource>
|
||||
{
|
||||
size_t operator()(const osrm::extractor::RestrictionSource &r_source) const
|
||||
{
|
||||
return hash_val(r_source.start_node, r_source.via_node);
|
||||
}
|
||||
};
|
||||
|
||||
template <> struct hash<osrm::extractor::RestrictionTarget>
|
||||
{
|
||||
size_t operator()(const osrm::extractor::RestrictionTarget &r_target) const
|
||||
{
|
||||
return hash_val(r_target.target_node, r_target.is_only);
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
namespace osrm
|
||||
{
|
||||
namespace extractor
|
||||
{
|
||||
/**
|
||||
\brief Efficent look up if an edge is the start + via node of a TurnRestriction
|
||||
EdgeBasedEdgeFactory decides by it if edges are inserted or geometry is compressed
|
||||
*/
|
||||
class RestrictionMap
|
||||
{
|
||||
public:
|
||||
RestrictionMap() : m_count(0) {}
|
||||
RestrictionMap(const std::vector<TurnRestriction> &restriction_list);
|
||||
|
||||
bool IsViaNode(const NodeID node) const;
|
||||
|
||||
// Check if edge (u, v) is the start of any turn restriction.
|
||||
// If so returns id of first target node.
|
||||
NodeID CheckForEmanatingIsOnlyTurn(const NodeID node_u, const NodeID node_v) const;
|
||||
// Checks if turn <u,v,w> is actually a turn restriction.
|
||||
bool
|
||||
CheckIfTurnIsRestricted(const NodeID node_u, const NodeID node_v, const NodeID node_w) const;
|
||||
|
||||
std::size_t size() const { return m_count; }
|
||||
|
||||
private:
|
||||
// check of node is the start of any restriction
|
||||
bool IsSourceNode(const NodeID node) const;
|
||||
|
||||
using EmanatingRestrictionsVector = std::vector<RestrictionTarget>;
|
||||
|
||||
std::size_t m_count;
|
||||
//! index -> list of (target, isOnly)
|
||||
std::vector<EmanatingRestrictionsVector> m_restriction_bucket_list;
|
||||
//! maps (start, via) -> bucket index
|
||||
std::unordered_map<RestrictionSource, unsigned> m_restriction_map;
|
||||
std::unordered_set<NodeID> m_restriction_start_nodes;
|
||||
std::unordered_set<NodeID> m_no_turn_via_node_set;
|
||||
};
|
||||
}
|
||||
}
|
||||
|
||||
#endif // RESTRICTION_MAP_HPP
|
||||
@@ -1,6 +1,7 @@
|
||||
#ifndef OSRM_EXTRACTOR_IO_HPP
|
||||
#define OSRM_EXTRACTOR_IO_HPP
|
||||
|
||||
#include "conditional_turn_penalty.hpp"
|
||||
#include "extractor/datasources.hpp"
|
||||
#include "extractor/intersection_bearings_container.hpp"
|
||||
#include "extractor/nbg_to_ebg.hpp"
|
||||
@@ -166,7 +167,9 @@ inline void write(storage::io::FileWriter &writer, const WayRestriction &restric
|
||||
inline void read(storage::io::FileReader &reader, TurnRestriction &restriction)
|
||||
{
|
||||
reader.ReadInto(restriction.is_only);
|
||||
if (restriction.Type() == RestrictionType::WAY_RESTRICTION)
|
||||
std::uint32_t restriction_type;
|
||||
reader.ReadInto(restriction_type);
|
||||
if (restriction_type == RestrictionType::WAY_RESTRICTION)
|
||||
{
|
||||
WayRestriction way_restriction;
|
||||
read(reader, way_restriction);
|
||||
@@ -174,7 +177,7 @@ inline void read(storage::io::FileReader &reader, TurnRestriction &restriction)
|
||||
}
|
||||
else
|
||||
{
|
||||
BOOST_ASSERT(restriction.Type() == RestrictionType::NODE_RESTRICTION);
|
||||
BOOST_ASSERT(restriction_type == RestrictionType::NODE_RESTRICTION);
|
||||
NodeRestriction node_restriction;
|
||||
read(reader, node_restriction);
|
||||
restriction.node_or_way = std::move(node_restriction);
|
||||
@@ -184,6 +187,8 @@ inline void read(storage::io::FileReader &reader, TurnRestriction &restriction)
|
||||
inline void write(storage::io::FileWriter &writer, const TurnRestriction &restriction)
|
||||
{
|
||||
writer.WriteOne(restriction.is_only);
|
||||
const std::uint32_t restriction_type = restriction.Type();
|
||||
writer.WriteOne(restriction_type);
|
||||
if (restriction.Type() == RestrictionType::WAY_RESTRICTION)
|
||||
{
|
||||
write(writer, mapbox::util::get<WayRestriction>(restriction.node_or_way));
|
||||
@@ -269,6 +274,54 @@ inline void write(storage::io::FileWriter &writer,
|
||||
};
|
||||
std::for_each(restrictions.begin(), restrictions.end(), write_restriction);
|
||||
}
|
||||
|
||||
inline void read(storage::io::FileReader &reader, ConditionalTurnPenalty &turn_penalty)
|
||||
{
|
||||
reader.ReadInto(turn_penalty.turn_offset);
|
||||
reader.ReadInto(turn_penalty.location.lat);
|
||||
reader.ReadInto(turn_penalty.location.lon);
|
||||
auto const num_conditions = reader.ReadElementCount64();
|
||||
turn_penalty.conditions.resize(num_conditions);
|
||||
for (auto &condition : turn_penalty.conditions)
|
||||
{
|
||||
reader.ReadInto(condition.modifier);
|
||||
storage::serialization::read(reader, condition.times);
|
||||
storage::serialization::read(reader, condition.weekdays);
|
||||
storage::serialization::read(reader, condition.monthdays);
|
||||
}
|
||||
}
|
||||
|
||||
inline void write(storage::io::FileWriter &writer, const ConditionalTurnPenalty &turn_penalty)
|
||||
{
|
||||
writer.WriteOne(turn_penalty.turn_offset);
|
||||
writer.WriteOne(static_cast<util::FixedLatitude::value_type>(turn_penalty.location.lat));
|
||||
writer.WriteOne(static_cast<util::FixedLongitude::value_type>(turn_penalty.location.lon));
|
||||
writer.WriteElementCount64(turn_penalty.conditions.size());
|
||||
for (const auto &c : turn_penalty.conditions)
|
||||
{
|
||||
writer.WriteOne(c.modifier);
|
||||
storage::serialization::write(writer, c.times);
|
||||
storage::serialization::write(writer, c.weekdays);
|
||||
storage::serialization::write(writer, c.monthdays);
|
||||
}
|
||||
}
|
||||
|
||||
inline void write(storage::io::FileWriter &writer,
|
||||
const std::vector<ConditionalTurnPenalty> &conditional_penalties)
|
||||
{
|
||||
writer.WriteElementCount64(conditional_penalties.size());
|
||||
for (const auto &penalty : conditional_penalties)
|
||||
write(writer, penalty);
|
||||
}
|
||||
|
||||
inline void read(storage::io::FileReader &reader,
|
||||
std::vector<ConditionalTurnPenalty> &conditional_penalties)
|
||||
{
|
||||
auto const num_elements = reader.ReadElementCount64();
|
||||
conditional_penalties.resize(num_elements);
|
||||
for (auto &penalty : conditional_penalties)
|
||||
read(reader, penalty);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -8,6 +8,7 @@
|
||||
#include <boost/unordered_map.hpp>
|
||||
|
||||
#include "extractor/restriction.hpp"
|
||||
#include "extractor/restriction_index.hpp"
|
||||
#include "util/integer_range.hpp"
|
||||
#include "util/typedefs.hpp"
|
||||
|
||||
@@ -18,6 +19,8 @@ namespace osrm
|
||||
namespace extractor
|
||||
{
|
||||
|
||||
// The WayRestrictionMap uses ConditionalTurnRestrictions in general. Most restrictions will have
|
||||
// empty conditions, though.
|
||||
class WayRestrictionMap
|
||||
{
|
||||
public:
|
||||
@@ -26,7 +29,7 @@ class WayRestrictionMap
|
||||
NodeID from;
|
||||
NodeID to;
|
||||
};
|
||||
WayRestrictionMap(const std::vector<TurnRestriction> &turn_restrictions);
|
||||
WayRestrictionMap(const std::vector<ConditionalTurnRestriction> &conditional_restrictions);
|
||||
|
||||
// Check if an edge between two nodes is a restricted turn. The check needs to be performed to
|
||||
// find duplicated nodes during the creation of edge-based-edges
|
||||
@@ -43,10 +46,13 @@ class WayRestrictionMap
|
||||
std::vector<ViaWay> DuplicatedNodeRepresentatives() const;
|
||||
|
||||
// Access all duplicated NodeIDs for a set of nodes indicating a via way
|
||||
util::range<DuplicatedNodeID> DuplicatedNodeIDs(const NodeID from, const NodeID to) const;
|
||||
std::vector<DuplicatedNodeID> DuplicatedNodeIDs(const NodeID from, const NodeID to) const;
|
||||
|
||||
// check whether a turn onto a given node is restricted, when coming from a duplicated node
|
||||
bool IsRestricted(DuplicatedNodeID duplicated_node, const NodeID to) const;
|
||||
// Get the restriction resulting in ^ IsRestricted. Requires IsRestricted to evaluate to true
|
||||
const ConditionalTurnRestriction &GetRestriction(DuplicatedNodeID duplicated_node,
|
||||
const NodeID to) const;
|
||||
|
||||
// changes edge_based_node to the correct duplicated_node_id in case node_based_from,
|
||||
// node_based_via, node_based_to can be identified with a restriction group
|
||||
@@ -76,11 +82,8 @@ class WayRestrictionMap
|
||||
// EBN: 0 . | 2 | 3 | 4 ...
|
||||
// duplicated node groups: ... | 5 | 7 | ...
|
||||
std::vector<DuplicatedNodeID> duplicated_node_groups;
|
||||
|
||||
boost::unordered_multimap<std::pair<NodeID, NodeID>, RestrictionID> restriction_starts;
|
||||
boost::unordered_multimap<std::pair<NodeID, NodeID>, RestrictionID> restriction_ends;
|
||||
|
||||
std::vector<TurnRestriction> restriction_data;
|
||||
std::vector<ConditionalTurnRestriction> restriction_data;
|
||||
RestrictionIndex<ConditionalTurnRestriction> restriction_starts;
|
||||
};
|
||||
|
||||
} // namespace extractor
|
||||
|
||||
@@ -97,7 +97,7 @@ template <typename T> void write(io::FileWriter &writer, const std::vector<T> &d
|
||||
{
|
||||
const auto count = data.size();
|
||||
writer.WriteElementCount64(count);
|
||||
return writer.WriteFrom(data.data(), count);
|
||||
writer.WriteFrom(data.data(), count);
|
||||
}
|
||||
|
||||
template <typename T> void read(io::FileReader &reader, util::vector_view<T> &data)
|
||||
|
||||
@@ -18,13 +18,13 @@ namespace util
|
||||
|
||||
struct NodeIdVectorToLineString
|
||||
{
|
||||
NodeIdVectorToLineString(const std::vector<extractor::QueryNode> &node_coordinates);
|
||||
NodeIdVectorToLineString(const std::vector<util::Coordinate> &node_coordinates);
|
||||
|
||||
// converts a vector of node ids into a linestring geojson feature
|
||||
util::json::Object operator()(const std::vector<NodeID> &node_ids,
|
||||
const boost::optional<json::Object> &properties = {}) const;
|
||||
|
||||
const std::vector<extractor::QueryNode> &node_coordinates;
|
||||
const std::vector<util::Coordinate> &node_coordinates;
|
||||
};
|
||||
|
||||
struct CoordinateVectorToLineString
|
||||
@@ -36,13 +36,13 @@ struct CoordinateVectorToLineString
|
||||
|
||||
struct NodeIdVectorToMultiPoint
|
||||
{
|
||||
NodeIdVectorToMultiPoint(const std::vector<extractor::QueryNode> &node_coordinates);
|
||||
NodeIdVectorToMultiPoint(const std::vector<util::Coordinate> &node_coordinates);
|
||||
|
||||
// converts a vector of node ids into a linestring geojson feature
|
||||
util::json::Object operator()(const std::vector<NodeID> &node_ids,
|
||||
const boost::optional<json::Object> &properties = {}) const;
|
||||
|
||||
const std::vector<extractor::QueryNode> &node_coordinates;
|
||||
const std::vector<util::Coordinate> &node_coordinates;
|
||||
};
|
||||
|
||||
struct CoordinateVectorToMultiPoint
|
||||
|
||||
@@ -69,12 +69,12 @@ struct CoordinateToJsonArray
|
||||
|
||||
struct NodeIdToCoordinate
|
||||
{
|
||||
NodeIdToCoordinate(const std::vector<extractor::QueryNode> &node_coordinates)
|
||||
NodeIdToCoordinate(const std::vector<util::Coordinate> &node_coordinates)
|
||||
: node_coordinates(node_coordinates)
|
||||
{
|
||||
}
|
||||
|
||||
const std::vector<extractor::QueryNode> &node_coordinates;
|
||||
const std::vector<util::Coordinate> &node_coordinates;
|
||||
|
||||
util::json::Array operator()(const NodeID nid)
|
||||
{
|
||||
|
||||
Generated
+2701
-1026
File diff suppressed because it is too large
Load Diff
+3
-2
@@ -1,6 +1,6 @@
|
||||
{
|
||||
"name": "osrm",
|
||||
"version": "5.10.0-rc.1",
|
||||
"version": "5.11.0",
|
||||
"private": false,
|
||||
"description": "The Open Source Routing Machine is a high performance routing engine written in C++14 designed to run on OpenStreetMap data.",
|
||||
"dependencies": {
|
||||
@@ -15,7 +15,7 @@
|
||||
]
|
||||
},
|
||||
"scripts": {
|
||||
"lint": "eslint -c ./.eslintrc features/step_definitions/ features/support/",
|
||||
"lint": "node ./node_modules/eslint/bin/eslint.js -c ./.eslintrc features/step_definitions/ features/support/",
|
||||
"test": "npm run lint && node ./node_modules/cucumber/bin/cucumber.js features/ -p verify && node ./node_modules/cucumber/bin/cucumber.js features/ -p mld",
|
||||
"clean": "rm -rf test/cache",
|
||||
"docs": "./scripts/build_api_docs.sh",
|
||||
@@ -37,6 +37,7 @@
|
||||
},
|
||||
"devDependencies": {
|
||||
"aws-sdk": "~2.0.31",
|
||||
"babel-plugin-transform-class-properties": "^6.24.1",
|
||||
"chalk": "^1.1.3",
|
||||
"cucumber": "^1.2.1",
|
||||
"d3-queue": "^2.0.3",
|
||||
|
||||
@@ -17,7 +17,7 @@ namespace
|
||||
{
|
||||
|
||||
// check bearings for u-turns.
|
||||
// since bearings are wrapped around at 0 (we only support 0,360), we need to do some minor math to
|
||||
// since bearings are wrapped around at 0 (we only support 0,360), we need to do some minor math to
|
||||
// check if bearings `a` and `b` go in opposite directions. In general we accept some minor
|
||||
// deviations for u-turns.
|
||||
bool bearingsAreReversed(const double bearing_in, const double bearing_out)
|
||||
@@ -123,7 +123,7 @@ bool isStaggeredIntersection(const RouteStepIterator step_prior_to_intersection,
|
||||
|
||||
const auto angle = [](const RouteStep &step) {
|
||||
const auto &intersection = step.intersections.front();
|
||||
const auto entry_bearing = intersection.bearings[intersection.in];
|
||||
const auto entry_bearing = util::bearing::reverse(intersection.bearings[intersection.in]);
|
||||
const auto exit_bearing = intersection.bearings[intersection.out];
|
||||
return util::bearing::angleBetween(entry_bearing, exit_bearing);
|
||||
};
|
||||
|
||||
@@ -158,6 +158,18 @@ void TransferTurnTypeStrategy::operator()(RouteStep &step_at_turn_location,
|
||||
void AdjustToCombinedTurnAngleStrategy::operator()(RouteStep &step_at_turn_location,
|
||||
const RouteStep &transfer_from_step) const
|
||||
{
|
||||
// Forks point to left/right. By doing a combined angle, we would risk ending up with
|
||||
// unreasonable fork instrucitons. The direction of a fork only depends on the forking location,
|
||||
// not further angles coming up
|
||||
//
|
||||
// d
|
||||
// . c
|
||||
// a - b
|
||||
//
|
||||
// could end up as `fork left` for `a-b-c`, instead of fork-right
|
||||
if (hasTurnType(step_at_turn_location, TurnType::Fork))
|
||||
return;
|
||||
|
||||
// TODO assert transfer_from_step == step_at_turn_location + 1
|
||||
const auto angle = findTotalTurnAngle(step_at_turn_location, transfer_from_step);
|
||||
step_at_turn_location.maneuver.instruction.direction_modifier = getTurnDirection(angle);
|
||||
@@ -173,7 +185,19 @@ void AdjustToCombinedTurnStrategy::operator()(RouteStep &step_at_turn_location,
|
||||
const RouteStep &transfer_from_step) const
|
||||
{
|
||||
const auto angle = findTotalTurnAngle(step_at_turn_location, transfer_from_step);
|
||||
const auto new_modifier = getTurnDirection(angle);
|
||||
|
||||
// Forks point to left/right. By doing a combined angle, we would risk ending up with
|
||||
// unreasonable fork instrucitons. The direction of a fork only depends on the forking location,
|
||||
// not further angles coming up
|
||||
//
|
||||
// d
|
||||
// . c
|
||||
// a - b
|
||||
//
|
||||
// could end up as `fork left` for `a-b-c`, instead of fork-right
|
||||
const auto new_modifier = hasTurnType(step_at_turn_location, TurnType::Fork)
|
||||
? step_at_turn_location.maneuver.instruction.direction_modifier
|
||||
: getTurnDirection(angle);
|
||||
|
||||
// a turn that is a new name or straight (turn/continue)
|
||||
const auto is_non_turn = [](const RouteStep &step) {
|
||||
|
||||
@@ -629,7 +629,21 @@ std::vector<RouteStep> buildIntersections(std::vector<RouteStep> steps)
|
||||
BOOST_ASSERT(step_index > 0);
|
||||
const auto &previous_step = steps[last_valid_instruction];
|
||||
if (previous_step.intersections.size() < MIN_END_OF_ROAD_INTERSECTIONS)
|
||||
step.maneuver.instruction.type = TurnType::Turn;
|
||||
{
|
||||
bool same_name =
|
||||
!(step.name.empty() && step.ref.empty()) &&
|
||||
!util::guidance::requiresNameAnnounced(previous_step.name,
|
||||
previous_step.ref,
|
||||
previous_step.pronunciation,
|
||||
previous_step.exits,
|
||||
step.name,
|
||||
step.ref,
|
||||
step.pronunciation,
|
||||
step.exits);
|
||||
|
||||
step.maneuver.instruction.type =
|
||||
same_name ? TurnType::Continue : TurnType::Turn;
|
||||
}
|
||||
}
|
||||
|
||||
// Remember the last non silent instruction
|
||||
|
||||
@@ -1,10 +1,6 @@
|
||||
#include "engine/routing_algorithms/shortest_path.hpp"
|
||||
#include "engine/routing_algorithms/routing_base_ch.hpp"
|
||||
#include "engine/routing_algorithms/routing_base_mld.hpp"
|
||||
|
||||
#include <boost/assert.hpp>
|
||||
#include <boost/optional.hpp>
|
||||
#include <memory>
|
||||
#include "engine/routing_algorithms/shortest_path_impl.hpp"
|
||||
|
||||
namespace osrm
|
||||
{
|
||||
@@ -13,449 +9,6 @@ namespace engine
|
||||
namespace routing_algorithms
|
||||
{
|
||||
|
||||
namespace
|
||||
{
|
||||
|
||||
const static constexpr bool DO_NOT_FORCE_LOOP = false;
|
||||
|
||||
// allows a uturn at the target_phantom
|
||||
// searches source forward/reverse -> target forward/reverse
|
||||
template <typename Algorithm>
|
||||
void searchWithUTurn(SearchEngineData<Algorithm> &engine_working_data,
|
||||
const DataFacade<Algorithm> &facade,
|
||||
typename SearchEngineData<Algorithm>::QueryHeap &forward_heap,
|
||||
typename SearchEngineData<Algorithm>::QueryHeap &reverse_heap,
|
||||
const bool search_from_forward_node,
|
||||
const bool search_from_reverse_node,
|
||||
const bool search_to_forward_node,
|
||||
const bool search_to_reverse_node,
|
||||
const PhantomNode &source_phantom,
|
||||
const PhantomNode &target_phantom,
|
||||
const int total_weight_to_forward,
|
||||
const int total_weight_to_reverse,
|
||||
int &new_total_weight,
|
||||
std::vector<NodeID> &leg_packed_path)
|
||||
{
|
||||
forward_heap.Clear();
|
||||
reverse_heap.Clear();
|
||||
if (search_from_forward_node)
|
||||
{
|
||||
forward_heap.Insert(source_phantom.forward_segment_id.id,
|
||||
-source_phantom.GetForwardWeightPlusOffset(),
|
||||
source_phantom.forward_segment_id.id);
|
||||
}
|
||||
if (search_from_reverse_node)
|
||||
{
|
||||
forward_heap.Insert(source_phantom.reverse_segment_id.id,
|
||||
-source_phantom.GetReverseWeightPlusOffset(),
|
||||
source_phantom.reverse_segment_id.id);
|
||||
}
|
||||
if (search_to_forward_node)
|
||||
{
|
||||
reverse_heap.Insert(target_phantom.forward_segment_id.id,
|
||||
target_phantom.GetForwardWeightPlusOffset(),
|
||||
target_phantom.forward_segment_id.id);
|
||||
}
|
||||
if (search_to_reverse_node)
|
||||
{
|
||||
reverse_heap.Insert(target_phantom.reverse_segment_id.id,
|
||||
target_phantom.GetReverseWeightPlusOffset(),
|
||||
target_phantom.reverse_segment_id.id);
|
||||
}
|
||||
|
||||
// this is only relevent if source and target are on the same compressed edge
|
||||
auto is_oneway_source = !(search_from_forward_node && search_from_reverse_node);
|
||||
auto is_oneway_target = !(search_to_forward_node && search_to_reverse_node);
|
||||
// we only enable loops here if we can't search from forward to backward node
|
||||
auto needs_loop_forwards = is_oneway_source && needsLoopForward(source_phantom, target_phantom);
|
||||
auto needs_loop_backwards =
|
||||
is_oneway_target && needsLoopBackwards(source_phantom, target_phantom);
|
||||
|
||||
search(engine_working_data,
|
||||
facade,
|
||||
forward_heap,
|
||||
reverse_heap,
|
||||
new_total_weight,
|
||||
leg_packed_path,
|
||||
needs_loop_forwards,
|
||||
needs_loop_backwards,
|
||||
{source_phantom, target_phantom});
|
||||
|
||||
// if no route is found between two parts of the via-route, the entire route becomes
|
||||
// invalid. Adding to invalid edge weight sadly doesn't return an invalid edge weight. Here
|
||||
// we prevent the possible overflow, faking the addition of infinity + x == infinity
|
||||
if (new_total_weight != INVALID_EDGE_WEIGHT)
|
||||
new_total_weight += std::min(total_weight_to_forward, total_weight_to_reverse);
|
||||
}
|
||||
|
||||
// searches shortest path between:
|
||||
// source forward/reverse -> target forward
|
||||
// source forward/reverse -> target reverse
|
||||
template <typename Algorithm>
|
||||
void search(SearchEngineData<Algorithm> &engine_working_data,
|
||||
const DataFacade<Algorithm> &facade,
|
||||
typename SearchEngineData<Algorithm>::QueryHeap &forward_heap,
|
||||
typename SearchEngineData<Algorithm>::QueryHeap &reverse_heap,
|
||||
const bool search_from_forward_node,
|
||||
const bool search_from_reverse_node,
|
||||
const bool search_to_forward_node,
|
||||
const bool search_to_reverse_node,
|
||||
const PhantomNode &source_phantom,
|
||||
const PhantomNode &target_phantom,
|
||||
const int total_weight_to_forward,
|
||||
const int total_weight_to_reverse,
|
||||
int &new_total_weight_to_forward,
|
||||
int &new_total_weight_to_reverse,
|
||||
std::vector<NodeID> &leg_packed_path_forward,
|
||||
std::vector<NodeID> &leg_packed_path_reverse)
|
||||
{
|
||||
if (search_to_forward_node)
|
||||
{
|
||||
forward_heap.Clear();
|
||||
reverse_heap.Clear();
|
||||
reverse_heap.Insert(target_phantom.forward_segment_id.id,
|
||||
target_phantom.GetForwardWeightPlusOffset(),
|
||||
target_phantom.forward_segment_id.id);
|
||||
|
||||
if (search_from_forward_node)
|
||||
{
|
||||
forward_heap.Insert(source_phantom.forward_segment_id.id,
|
||||
total_weight_to_forward -
|
||||
source_phantom.GetForwardWeightPlusOffset(),
|
||||
source_phantom.forward_segment_id.id);
|
||||
}
|
||||
if (search_from_reverse_node)
|
||||
{
|
||||
forward_heap.Insert(source_phantom.reverse_segment_id.id,
|
||||
total_weight_to_reverse -
|
||||
source_phantom.GetReverseWeightPlusOffset(),
|
||||
source_phantom.reverse_segment_id.id);
|
||||
}
|
||||
|
||||
search(engine_working_data,
|
||||
facade,
|
||||
forward_heap,
|
||||
reverse_heap,
|
||||
new_total_weight_to_forward,
|
||||
leg_packed_path_forward,
|
||||
needsLoopForward(source_phantom, target_phantom),
|
||||
routing_algorithms::DO_NOT_FORCE_LOOP,
|
||||
{source_phantom, target_phantom});
|
||||
}
|
||||
|
||||
if (search_to_reverse_node)
|
||||
{
|
||||
forward_heap.Clear();
|
||||
reverse_heap.Clear();
|
||||
reverse_heap.Insert(target_phantom.reverse_segment_id.id,
|
||||
target_phantom.GetReverseWeightPlusOffset(),
|
||||
target_phantom.reverse_segment_id.id);
|
||||
if (search_from_forward_node)
|
||||
{
|
||||
forward_heap.Insert(source_phantom.forward_segment_id.id,
|
||||
total_weight_to_forward -
|
||||
source_phantom.GetForwardWeightPlusOffset(),
|
||||
source_phantom.forward_segment_id.id);
|
||||
}
|
||||
if (search_from_reverse_node)
|
||||
{
|
||||
forward_heap.Insert(source_phantom.reverse_segment_id.id,
|
||||
total_weight_to_reverse -
|
||||
source_phantom.GetReverseWeightPlusOffset(),
|
||||
source_phantom.reverse_segment_id.id);
|
||||
}
|
||||
|
||||
search(engine_working_data,
|
||||
facade,
|
||||
forward_heap,
|
||||
reverse_heap,
|
||||
new_total_weight_to_reverse,
|
||||
leg_packed_path_reverse,
|
||||
routing_algorithms::DO_NOT_FORCE_LOOP,
|
||||
needsLoopBackwards(source_phantom, target_phantom),
|
||||
{source_phantom, target_phantom});
|
||||
}
|
||||
}
|
||||
|
||||
template <typename Algorithm>
|
||||
void unpackLegs(const DataFacade<Algorithm> &facade,
|
||||
const std::vector<PhantomNodes> &phantom_nodes_vector,
|
||||
const std::vector<NodeID> &total_packed_path,
|
||||
const std::vector<std::size_t> &packed_leg_begin,
|
||||
const EdgeWeight shortest_path_weight,
|
||||
InternalRouteResult &raw_route_data)
|
||||
{
|
||||
raw_route_data.unpacked_path_segments.resize(packed_leg_begin.size() - 1);
|
||||
|
||||
raw_route_data.shortest_path_weight = shortest_path_weight;
|
||||
|
||||
for (const auto current_leg : util::irange<std::size_t>(0UL, packed_leg_begin.size() - 1))
|
||||
{
|
||||
auto leg_begin = total_packed_path.begin() + packed_leg_begin[current_leg];
|
||||
auto leg_end = total_packed_path.begin() + packed_leg_begin[current_leg + 1];
|
||||
const auto &unpack_phantom_node_pair = phantom_nodes_vector[current_leg];
|
||||
unpackPath(facade,
|
||||
leg_begin,
|
||||
leg_end,
|
||||
unpack_phantom_node_pair,
|
||||
raw_route_data.unpacked_path_segments[current_leg]);
|
||||
|
||||
raw_route_data.source_traversed_in_reverse.push_back(
|
||||
(*leg_begin != phantom_nodes_vector[current_leg].source_phantom.forward_segment_id.id));
|
||||
raw_route_data.target_traversed_in_reverse.push_back(
|
||||
(*std::prev(leg_end) !=
|
||||
phantom_nodes_vector[current_leg].target_phantom.forward_segment_id.id));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
template <typename Algorithm>
|
||||
InternalRouteResult shortestPathSearch(SearchEngineData<Algorithm> &engine_working_data,
|
||||
const DataFacade<Algorithm> &facade,
|
||||
const std::vector<PhantomNodes> &phantom_nodes_vector,
|
||||
const boost::optional<bool> continue_straight_at_waypoint)
|
||||
{
|
||||
InternalRouteResult raw_route_data;
|
||||
raw_route_data.segment_end_coordinates = phantom_nodes_vector;
|
||||
const bool allow_uturn_at_waypoint =
|
||||
!(continue_straight_at_waypoint ? *continue_straight_at_waypoint
|
||||
: facade.GetContinueStraightDefault());
|
||||
|
||||
engine_working_data.InitializeOrClearFirstThreadLocalStorage(facade.GetNumberOfNodes());
|
||||
|
||||
auto &forward_heap = *engine_working_data.forward_heap_1;
|
||||
auto &reverse_heap = *engine_working_data.reverse_heap_1;
|
||||
|
||||
int total_weight_to_forward = 0;
|
||||
int total_weight_to_reverse = 0;
|
||||
bool search_from_forward_node =
|
||||
phantom_nodes_vector.front().source_phantom.IsValidForwardSource();
|
||||
bool search_from_reverse_node =
|
||||
phantom_nodes_vector.front().source_phantom.IsValidReverseSource();
|
||||
|
||||
std::vector<NodeID> prev_packed_leg_to_forward;
|
||||
std::vector<NodeID> prev_packed_leg_to_reverse;
|
||||
|
||||
std::vector<NodeID> total_packed_path_to_forward;
|
||||
std::vector<std::size_t> packed_leg_to_forward_begin;
|
||||
std::vector<NodeID> total_packed_path_to_reverse;
|
||||
std::vector<std::size_t> packed_leg_to_reverse_begin;
|
||||
|
||||
std::size_t current_leg = 0;
|
||||
// this implements a dynamic program that finds the shortest route through
|
||||
// a list of vias
|
||||
for (const auto &phantom_node_pair : phantom_nodes_vector)
|
||||
{
|
||||
int new_total_weight_to_forward = INVALID_EDGE_WEIGHT;
|
||||
int new_total_weight_to_reverse = INVALID_EDGE_WEIGHT;
|
||||
|
||||
std::vector<NodeID> packed_leg_to_forward;
|
||||
std::vector<NodeID> packed_leg_to_reverse;
|
||||
|
||||
const auto &source_phantom = phantom_node_pair.source_phantom;
|
||||
const auto &target_phantom = phantom_node_pair.target_phantom;
|
||||
|
||||
bool search_to_forward_node = target_phantom.IsValidForwardTarget();
|
||||
bool search_to_reverse_node = target_phantom.IsValidReverseTarget();
|
||||
|
||||
BOOST_ASSERT(!search_from_forward_node || source_phantom.IsValidForwardSource());
|
||||
BOOST_ASSERT(!search_from_reverse_node || source_phantom.IsValidReverseSource());
|
||||
|
||||
if (search_to_reverse_node || search_to_forward_node)
|
||||
{
|
||||
if (allow_uturn_at_waypoint)
|
||||
{
|
||||
searchWithUTurn(engine_working_data,
|
||||
facade,
|
||||
forward_heap,
|
||||
reverse_heap,
|
||||
search_from_forward_node,
|
||||
search_from_reverse_node,
|
||||
search_to_forward_node,
|
||||
search_to_reverse_node,
|
||||
source_phantom,
|
||||
target_phantom,
|
||||
total_weight_to_forward,
|
||||
total_weight_to_reverse,
|
||||
new_total_weight_to_forward,
|
||||
packed_leg_to_forward);
|
||||
// if only the reverse node is valid (e.g. when using the match plugin) we
|
||||
// actually need to move
|
||||
if (!target_phantom.IsValidForwardTarget())
|
||||
{
|
||||
BOOST_ASSERT(target_phantom.IsValidReverseTarget());
|
||||
new_total_weight_to_reverse = new_total_weight_to_forward;
|
||||
packed_leg_to_reverse = std::move(packed_leg_to_forward);
|
||||
new_total_weight_to_forward = INVALID_EDGE_WEIGHT;
|
||||
|
||||
// (*)
|
||||
//
|
||||
// Below we have to check if new_total_weight_to_forward is invalid.
|
||||
// This prevents use-after-move on packed_leg_to_forward.
|
||||
}
|
||||
else if (target_phantom.IsValidReverseTarget())
|
||||
{
|
||||
new_total_weight_to_reverse = new_total_weight_to_forward;
|
||||
packed_leg_to_reverse = packed_leg_to_forward;
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
search(engine_working_data,
|
||||
facade,
|
||||
forward_heap,
|
||||
reverse_heap,
|
||||
search_from_forward_node,
|
||||
search_from_reverse_node,
|
||||
search_to_forward_node,
|
||||
search_to_reverse_node,
|
||||
source_phantom,
|
||||
target_phantom,
|
||||
total_weight_to_forward,
|
||||
total_weight_to_reverse,
|
||||
new_total_weight_to_forward,
|
||||
new_total_weight_to_reverse,
|
||||
packed_leg_to_forward,
|
||||
packed_leg_to_reverse);
|
||||
}
|
||||
}
|
||||
|
||||
// Note: To make sure we do not access the moved-from packed_leg_to_forward
|
||||
// we guard its access by a check for invalid edge weight. See (*) above.
|
||||
|
||||
// No path found for both target nodes?
|
||||
if ((INVALID_EDGE_WEIGHT == new_total_weight_to_forward) &&
|
||||
(INVALID_EDGE_WEIGHT == new_total_weight_to_reverse))
|
||||
{
|
||||
return raw_route_data;
|
||||
}
|
||||
|
||||
// we need to figure out how the new legs connect to the previous ones
|
||||
if (current_leg > 0)
|
||||
{
|
||||
bool forward_to_forward =
|
||||
(new_total_weight_to_forward != INVALID_EDGE_WEIGHT) &&
|
||||
packed_leg_to_forward.front() == source_phantom.forward_segment_id.id;
|
||||
bool reverse_to_forward =
|
||||
(new_total_weight_to_forward != INVALID_EDGE_WEIGHT) &&
|
||||
packed_leg_to_forward.front() == source_phantom.reverse_segment_id.id;
|
||||
bool forward_to_reverse =
|
||||
(new_total_weight_to_reverse != INVALID_EDGE_WEIGHT) &&
|
||||
packed_leg_to_reverse.front() == source_phantom.forward_segment_id.id;
|
||||
bool reverse_to_reverse =
|
||||
(new_total_weight_to_reverse != INVALID_EDGE_WEIGHT) &&
|
||||
packed_leg_to_reverse.front() == source_phantom.reverse_segment_id.id;
|
||||
|
||||
BOOST_ASSERT(!forward_to_forward || !reverse_to_forward);
|
||||
BOOST_ASSERT(!forward_to_reverse || !reverse_to_reverse);
|
||||
|
||||
// in this case we always need to copy
|
||||
if (forward_to_forward && forward_to_reverse)
|
||||
{
|
||||
// in this case we copy the path leading to the source forward node
|
||||
// and change the case
|
||||
total_packed_path_to_reverse = total_packed_path_to_forward;
|
||||
packed_leg_to_reverse_begin = packed_leg_to_forward_begin;
|
||||
forward_to_reverse = false;
|
||||
reverse_to_reverse = true;
|
||||
}
|
||||
else if (reverse_to_forward && reverse_to_reverse)
|
||||
{
|
||||
total_packed_path_to_forward = total_packed_path_to_reverse;
|
||||
packed_leg_to_forward_begin = packed_leg_to_reverse_begin;
|
||||
reverse_to_forward = false;
|
||||
forward_to_forward = true;
|
||||
}
|
||||
BOOST_ASSERT(!forward_to_forward || !forward_to_reverse);
|
||||
BOOST_ASSERT(!reverse_to_forward || !reverse_to_reverse);
|
||||
|
||||
// in this case we just need to swap to regain the correct mapping
|
||||
if (reverse_to_forward || forward_to_reverse)
|
||||
{
|
||||
total_packed_path_to_forward.swap(total_packed_path_to_reverse);
|
||||
packed_leg_to_forward_begin.swap(packed_leg_to_reverse_begin);
|
||||
}
|
||||
}
|
||||
|
||||
if (new_total_weight_to_forward != INVALID_EDGE_WEIGHT)
|
||||
{
|
||||
BOOST_ASSERT(target_phantom.IsValidForwardTarget());
|
||||
|
||||
packed_leg_to_forward_begin.push_back(total_packed_path_to_forward.size());
|
||||
total_packed_path_to_forward.insert(total_packed_path_to_forward.end(),
|
||||
packed_leg_to_forward.begin(),
|
||||
packed_leg_to_forward.end());
|
||||
search_from_forward_node = true;
|
||||
}
|
||||
else
|
||||
{
|
||||
total_packed_path_to_forward.clear();
|
||||
packed_leg_to_forward_begin.clear();
|
||||
search_from_forward_node = false;
|
||||
}
|
||||
|
||||
if (new_total_weight_to_reverse != INVALID_EDGE_WEIGHT)
|
||||
{
|
||||
BOOST_ASSERT(target_phantom.IsValidReverseTarget());
|
||||
|
||||
packed_leg_to_reverse_begin.push_back(total_packed_path_to_reverse.size());
|
||||
total_packed_path_to_reverse.insert(total_packed_path_to_reverse.end(),
|
||||
packed_leg_to_reverse.begin(),
|
||||
packed_leg_to_reverse.end());
|
||||
search_from_reverse_node = true;
|
||||
}
|
||||
else
|
||||
{
|
||||
total_packed_path_to_reverse.clear();
|
||||
packed_leg_to_reverse_begin.clear();
|
||||
search_from_reverse_node = false;
|
||||
}
|
||||
|
||||
prev_packed_leg_to_forward = std::move(packed_leg_to_forward);
|
||||
prev_packed_leg_to_reverse = std::move(packed_leg_to_reverse);
|
||||
|
||||
total_weight_to_forward = new_total_weight_to_forward;
|
||||
total_weight_to_reverse = new_total_weight_to_reverse;
|
||||
|
||||
++current_leg;
|
||||
}
|
||||
|
||||
BOOST_ASSERT(total_weight_to_forward != INVALID_EDGE_WEIGHT ||
|
||||
total_weight_to_reverse != INVALID_EDGE_WEIGHT);
|
||||
|
||||
// We make sure the fastest route is always in packed_legs_to_forward
|
||||
if (total_weight_to_forward < total_weight_to_reverse ||
|
||||
(total_weight_to_forward == total_weight_to_reverse &&
|
||||
total_packed_path_to_forward.size() < total_packed_path_to_reverse.size()))
|
||||
{
|
||||
// insert sentinel
|
||||
packed_leg_to_forward_begin.push_back(total_packed_path_to_forward.size());
|
||||
BOOST_ASSERT(packed_leg_to_forward_begin.size() == phantom_nodes_vector.size() + 1);
|
||||
|
||||
unpackLegs(facade,
|
||||
phantom_nodes_vector,
|
||||
total_packed_path_to_forward,
|
||||
packed_leg_to_forward_begin,
|
||||
total_weight_to_forward,
|
||||
raw_route_data);
|
||||
}
|
||||
else
|
||||
{
|
||||
// insert sentinel
|
||||
packed_leg_to_reverse_begin.push_back(total_packed_path_to_reverse.size());
|
||||
BOOST_ASSERT(packed_leg_to_reverse_begin.size() == phantom_nodes_vector.size() + 1);
|
||||
|
||||
unpackLegs(facade,
|
||||
phantom_nodes_vector,
|
||||
total_packed_path_to_reverse,
|
||||
packed_leg_to_reverse_begin,
|
||||
total_weight_to_reverse,
|
||||
raw_route_data);
|
||||
}
|
||||
|
||||
return raw_route_data;
|
||||
}
|
||||
|
||||
template InternalRouteResult
|
||||
shortestPathSearch(SearchEngineData<ch::Algorithm> &engine_working_data,
|
||||
const DataFacade<ch::Algorithm> &facade,
|
||||
|
||||
@@ -103,14 +103,17 @@ SegmentDuration CompressedEdgeContainer::ClipDuration(const SegmentDuration dura
|
||||
// ----------> via_node_id -----------> target_node_id
|
||||
// weight_1 weight_2
|
||||
// duration_1 duration_2
|
||||
void CompressedEdgeContainer::CompressEdge(const EdgeID edge_id_1,
|
||||
const EdgeID edge_id_2,
|
||||
const NodeID via_node_id,
|
||||
const NodeID target_node_id,
|
||||
const EdgeWeight weight1,
|
||||
const EdgeWeight weight2,
|
||||
const EdgeDuration duration1,
|
||||
const EdgeDuration duration2)
|
||||
void CompressedEdgeContainer::CompressEdge(
|
||||
const EdgeID edge_id_1,
|
||||
const EdgeID edge_id_2,
|
||||
const NodeID via_node_id,
|
||||
const NodeID target_node_id,
|
||||
const EdgeWeight weight1,
|
||||
const EdgeWeight weight2,
|
||||
const EdgeDuration duration1,
|
||||
const EdgeDuration duration2,
|
||||
const boost::optional<EdgeWeight> node_weight_penalty,
|
||||
const boost::optional<EdgeDuration> node_duration_penalty)
|
||||
{
|
||||
// remove super-trivial geometries
|
||||
BOOST_ASSERT(SPECIAL_EDGEID != edge_id_1);
|
||||
@@ -151,9 +154,11 @@ void CompressedEdgeContainer::CompressEdge(const EdgeID edge_id_1,
|
||||
std::vector<OnewayCompressedEdge> &edge_bucket_list1 =
|
||||
m_compressed_oneway_geometries[edge_bucket_id1];
|
||||
|
||||
bool was_empty = edge_bucket_list1.empty();
|
||||
|
||||
// note we don't save the start coordinate: it is implicitly given by edge 1
|
||||
// weight1 is the distance to the (currently) last coordinate in the bucket
|
||||
if (edge_bucket_list1.empty())
|
||||
if (was_empty)
|
||||
{
|
||||
edge_bucket_list1.emplace_back(
|
||||
OnewayCompressedEdge{via_node_id, ClipWeight(weight1), ClipDuration(duration1)});
|
||||
@@ -162,6 +167,14 @@ void CompressedEdgeContainer::CompressEdge(const EdgeID edge_id_1,
|
||||
BOOST_ASSERT(0 < edge_bucket_list1.size());
|
||||
BOOST_ASSERT(!edge_bucket_list1.empty());
|
||||
|
||||
// if the via-node offers a penalty, we add the weight of the penalty as an artificial
|
||||
// segment that references SPECIAL_NODEID
|
||||
if (node_weight_penalty && node_duration_penalty)
|
||||
{
|
||||
edge_bucket_list1.emplace_back(OnewayCompressedEdge{
|
||||
via_node_id, ClipWeight(*node_weight_penalty), ClipDuration(*node_duration_penalty)});
|
||||
}
|
||||
|
||||
if (HasEntryForID(edge_id_2))
|
||||
{
|
||||
// second edge is not atomic anymore
|
||||
|
||||
@@ -1,4 +1,5 @@
|
||||
#include "extractor/edge_based_graph_factory.hpp"
|
||||
#include "extractor/conditional_turn_penalty.hpp"
|
||||
#include "extractor/edge_based_edge.hpp"
|
||||
#include "extractor/files.hpp"
|
||||
#include "extractor/guidance/turn_analysis.hpp"
|
||||
@@ -6,6 +7,7 @@
|
||||
#include "extractor/scripting_environment.hpp"
|
||||
#include "extractor/suffix_table.hpp"
|
||||
|
||||
#include "extractor/serialization.hpp"
|
||||
#include "storage/io.hpp"
|
||||
|
||||
#include "util/assert.hpp"
|
||||
@@ -20,8 +22,10 @@
|
||||
#include "util/timing_util.hpp"
|
||||
|
||||
#include <boost/assert.hpp>
|
||||
#include <boost/functional/hash.hpp>
|
||||
#include <boost/numeric/conversion/cast.hpp>
|
||||
|
||||
#include "boost/unordered_map.hpp"
|
||||
#include <algorithm>
|
||||
#include <cmath>
|
||||
#include <iomanip>
|
||||
@@ -35,12 +39,26 @@
|
||||
#include <tbb/pipeline.h>
|
||||
#include <tbb/task_scheduler_init.h>
|
||||
|
||||
namespace std
|
||||
{
|
||||
template <> struct hash<std::pair<NodeID, NodeID>>
|
||||
{
|
||||
std::size_t operator()(const std::pair<NodeID, NodeID> &mk) const noexcept
|
||||
{
|
||||
std::size_t seed = 0;
|
||||
boost::hash_combine(seed, mk.first);
|
||||
boost::hash_combine(seed, mk.second);
|
||||
return seed;
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
namespace osrm
|
||||
{
|
||||
namespace extractor
|
||||
{
|
||||
// Configuration to find representative candidate for turn angle calculations
|
||||
|
||||
// Configuration to find representative candidate for turn angle calculations
|
||||
EdgeBasedGraphFactory::EdgeBasedGraphFactory(
|
||||
std::shared_ptr<util::NodeBasedDynamicGraph> node_based_graph,
|
||||
CompressedEdgeContainer &compressed_edge_container,
|
||||
@@ -168,6 +186,11 @@ NBGToEBG EdgeBasedGraphFactory::InsertEdgeBasedNode(const NodeID node_u, const N
|
||||
m_compressed_edge_container.GetBucketReference(edge_id_2)[segment_count - 1 - i]
|
||||
.node_id);
|
||||
const NodeID current_edge_target_coordinate_id = forward_geometry[i].node_id;
|
||||
|
||||
// don't add node-segments for penalties
|
||||
if (current_edge_target_coordinate_id == current_edge_source_coordinate_id)
|
||||
continue;
|
||||
|
||||
BOOST_ASSERT(current_edge_target_coordinate_id != current_edge_source_coordinate_id);
|
||||
|
||||
// build edges
|
||||
@@ -194,7 +217,9 @@ void EdgeBasedGraphFactory::Run(ScriptingEnvironment &scripting_environment,
|
||||
const std::string &turn_duration_penalties_filename,
|
||||
const std::string &turn_penalties_index_filename,
|
||||
const std::string &cnbg_ebg_mapping_path,
|
||||
const std::string &conditional_penalties_filename,
|
||||
const RestrictionMap &node_restriction_map,
|
||||
const ConditionalRestrictionMap &conditional_node_restriction_map,
|
||||
const WayRestrictionMap &way_restriction_map)
|
||||
{
|
||||
TIMER_START(renumber);
|
||||
@@ -215,7 +240,9 @@ void EdgeBasedGraphFactory::Run(ScriptingEnvironment &scripting_environment,
|
||||
turn_weight_penalties_filename,
|
||||
turn_duration_penalties_filename,
|
||||
turn_penalties_index_filename,
|
||||
conditional_penalties_filename,
|
||||
node_restriction_map,
|
||||
conditional_node_restriction_map,
|
||||
way_restriction_map);
|
||||
|
||||
TIMER_STOP(generate_edges);
|
||||
@@ -379,7 +406,9 @@ void EdgeBasedGraphFactory::GenerateEdgeExpandedEdges(
|
||||
const std::string &turn_weight_penalties_filename,
|
||||
const std::string &turn_duration_penalties_filename,
|
||||
const std::string &turn_penalties_index_filename,
|
||||
const std::string &conditional_penalties_filename,
|
||||
const RestrictionMap &node_restriction_map,
|
||||
const ConditionalRestrictionMap &conditional_restriction_map,
|
||||
const WayRestrictionMap &way_restriction_map)
|
||||
{
|
||||
|
||||
@@ -422,6 +451,8 @@ void EdgeBasedGraphFactory::GenerateEdgeExpandedEdges(
|
||||
const auto weight_multiplier =
|
||||
scripting_environment.GetProfileProperties().GetWeightMultiplier();
|
||||
|
||||
// filled in during next stage, kept alive through following scope
|
||||
std::vector<Conditional> conditionals;
|
||||
// The following block generates the edge-based-edges using a parallel processing
|
||||
// pipeline. Sets of intersection IDs are batched in groups of GRAINSIZE (100)
|
||||
// `generator_stage`,
|
||||
@@ -477,7 +508,7 @@ void EdgeBasedGraphFactory::GenerateEdgeExpandedEdges(
|
||||
};
|
||||
|
||||
// same as IntersectionData, but grouped with edge to allow sorting after creating. Edges
|
||||
// are out of order
|
||||
// can be out of order
|
||||
struct EdgeWithData
|
||||
{
|
||||
EdgeBasedEdge edge;
|
||||
@@ -492,10 +523,14 @@ void EdgeBasedGraphFactory::GenerateEdgeExpandedEdges(
|
||||
std::size_t nodes_processed = 0;
|
||||
IntersectionData continuous_data;
|
||||
std::vector<EdgeWithData> delayed_data;
|
||||
std::vector<Conditional> conditionals;
|
||||
};
|
||||
|
||||
// Generate edges for either artificial nodes or the main graph
|
||||
const auto generate_edge = [this, &scripting_environment, weight_multiplier](
|
||||
const auto generate_edge = [this,
|
||||
&scripting_environment,
|
||||
weight_multiplier,
|
||||
&conditional_restriction_map](
|
||||
// what nodes will be used? In most cases this will be the id stored in the edge_data.
|
||||
// In case of duplicated nodes (e.g. due to via-way restrictions), one/both of these
|
||||
// might refer to a newly added edge based node
|
||||
@@ -509,6 +544,24 @@ void EdgeBasedGraphFactory::GenerateEdgeExpandedEdges(
|
||||
const auto &intersection,
|
||||
const auto &turn,
|
||||
const auto entry_class_id) {
|
||||
|
||||
const auto node_restricted = isRestricted(node_along_road_entering,
|
||||
node_at_center_of_intersection,
|
||||
m_node_based_graph->GetTarget(turn.eid),
|
||||
conditional_restriction_map);
|
||||
|
||||
boost::optional<Conditional> conditional = boost::none;
|
||||
if (node_restricted.first)
|
||||
{
|
||||
auto const &conditions = node_restricted.second->condition;
|
||||
// get conditions of the restriction limiting the node
|
||||
conditional = {{edge_based_node_from,
|
||||
edge_based_node_to,
|
||||
{static_cast<std::uint64_t>(-1),
|
||||
m_coordinates[node_at_center_of_intersection],
|
||||
conditions}}};
|
||||
}
|
||||
|
||||
const EdgeData &edge_data1 = m_node_based_graph->GetEdgeData(node_based_edge_from);
|
||||
const EdgeData &edge_data2 = m_node_based_graph->GetEdgeData(node_based_edge_to);
|
||||
|
||||
@@ -568,15 +621,16 @@ void EdgeBasedGraphFactory::GenerateEdgeExpandedEdges(
|
||||
const auto &from_node =
|
||||
isTrivial ? node_along_road_entering
|
||||
: m_compressed_edge_container.GetLastEdgeSourceID(node_based_edge_from);
|
||||
const auto &via_node =
|
||||
m_compressed_edge_container.GetLastEdgeTargetID(node_based_edge_from);
|
||||
const auto &to_node = m_compressed_edge_container.GetFirstEdgeTargetID(turn.eid);
|
||||
|
||||
lookup::TurnIndexBlock turn_index_block = {from_node, via_node, to_node};
|
||||
lookup::TurnIndexBlock turn_index_block = {
|
||||
from_node, node_at_center_of_intersection, to_node};
|
||||
|
||||
// insert data into the designated buffer
|
||||
return EdgeWithData{
|
||||
edge_based_edge, turn_index_block, weight_penalty, duration_penalty, turn_data};
|
||||
return std::make_pair(
|
||||
EdgeWithData{
|
||||
edge_based_edge, turn_index_block, weight_penalty, duration_penalty, turn_data},
|
||||
conditional);
|
||||
};
|
||||
|
||||
// Second part of the pipeline is where the intersection analysis is done for
|
||||
@@ -715,7 +769,7 @@ void EdgeBasedGraphFactory::GenerateEdgeExpandedEdges(
|
||||
m_number_of_edge_based_nodes);
|
||||
|
||||
{ // scope to forget edge_with_data after
|
||||
const auto edge_with_data =
|
||||
const auto edge_with_data_and_condition =
|
||||
generate_edge(edge_data1.edge_id,
|
||||
target_id,
|
||||
node_along_road_entering,
|
||||
@@ -726,15 +780,21 @@ void EdgeBasedGraphFactory::GenerateEdgeExpandedEdges(
|
||||
turn,
|
||||
entry_class_id);
|
||||
|
||||
buffer->continuous_data.edges_list.push_back(edge_with_data.edge);
|
||||
buffer->continuous_data.edges_list.push_back(
|
||||
edge_with_data_and_condition.first.edge);
|
||||
buffer->continuous_data.turn_indexes.push_back(
|
||||
edge_with_data.turn_index);
|
||||
edge_with_data_and_condition.first.turn_index);
|
||||
buffer->continuous_data.turn_weight_penalties.push_back(
|
||||
edge_with_data.turn_weight_penalty);
|
||||
edge_with_data_and_condition.first.turn_weight_penalty);
|
||||
buffer->continuous_data.turn_duration_penalties.push_back(
|
||||
edge_with_data.turn_duration_penalty);
|
||||
edge_with_data_and_condition.first.turn_duration_penalty);
|
||||
buffer->continuous_data.turn_data_container.push_back(
|
||||
edge_with_data.turn_data);
|
||||
edge_with_data_and_condition.first.turn_data);
|
||||
if (edge_with_data_and_condition.second)
|
||||
{
|
||||
buffer->conditionals.push_back(
|
||||
*edge_with_data_and_condition.second);
|
||||
}
|
||||
}
|
||||
|
||||
// when turning off a a via-way turn restriction, we need to not only
|
||||
@@ -749,24 +809,30 @@ void EdgeBasedGraphFactory::GenerateEdgeExpandedEdges(
|
||||
// next to the normal restrictions tracked in `entry_allowed`, via
|
||||
// ways might introduce additional restrictions. These are handled
|
||||
// here when turning off a via-way
|
||||
const auto add_unrestricted_turns =
|
||||
[&](const auto duplicated_node_id) {
|
||||
const auto from_id =
|
||||
m_number_of_edge_based_nodes -
|
||||
way_restriction_map.NumberOfDuplicatedNodes() +
|
||||
duplicated_node_id;
|
||||
for (auto duplicated_node_id : duplicated_nodes)
|
||||
{
|
||||
const auto from_id =
|
||||
m_number_of_edge_based_nodes -
|
||||
way_restriction_map.NumberOfDuplicatedNodes() +
|
||||
duplicated_node_id;
|
||||
|
||||
auto const node_at_end_of_turn =
|
||||
m_node_based_graph->GetTarget(turn.eid);
|
||||
auto const node_at_end_of_turn =
|
||||
m_node_based_graph->GetTarget(turn.eid);
|
||||
|
||||
const auto is_restricted = way_restriction_map.IsRestricted(
|
||||
const auto is_way_restricted = way_restriction_map.IsRestricted(
|
||||
duplicated_node_id, node_at_end_of_turn);
|
||||
|
||||
if (is_way_restricted)
|
||||
{
|
||||
|
||||
auto const restriction = way_restriction_map.GetRestriction(
|
||||
duplicated_node_id, node_at_end_of_turn);
|
||||
|
||||
if (is_restricted)
|
||||
return;
|
||||
if (restriction.condition.empty())
|
||||
continue;
|
||||
|
||||
// add into delayed data
|
||||
auto edge_with_data = generate_edge(
|
||||
auto edge_with_data_and_condition = generate_edge(
|
||||
NodeID(from_id),
|
||||
m_node_based_graph->GetEdgeData(turn.eid).edge_id,
|
||||
node_along_road_entering,
|
||||
@@ -777,12 +843,50 @@ void EdgeBasedGraphFactory::GenerateEdgeExpandedEdges(
|
||||
turn,
|
||||
entry_class_id);
|
||||
|
||||
buffer->delayed_data.push_back(std::move(edge_with_data));
|
||||
};
|
||||
buffer->delayed_data.push_back(
|
||||
std::move(edge_with_data_and_condition.first));
|
||||
|
||||
std::for_each(duplicated_nodes.begin(),
|
||||
duplicated_nodes.end(),
|
||||
add_unrestricted_turns);
|
||||
if (edge_with_data_and_condition.second)
|
||||
{
|
||||
buffer->conditionals.push_back(
|
||||
*edge_with_data_and_condition.second);
|
||||
}
|
||||
|
||||
// also add the conditions for the way
|
||||
if (is_way_restricted && !restriction.condition.empty())
|
||||
{
|
||||
// add a new conditional for the edge we just created
|
||||
buffer->conditionals.push_back(
|
||||
{NodeID(from_id),
|
||||
m_node_based_graph->GetEdgeData(turn.eid).edge_id,
|
||||
{static_cast<std::uint64_t>(-1),
|
||||
m_coordinates[node_at_center_of_intersection],
|
||||
restriction.condition}});
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
auto edge_with_data_and_condition = generate_edge(
|
||||
NodeID(from_id),
|
||||
m_node_based_graph->GetEdgeData(turn.eid).edge_id,
|
||||
node_along_road_entering,
|
||||
incoming_edge,
|
||||
node_at_center_of_intersection,
|
||||
turn.eid,
|
||||
intersection,
|
||||
turn,
|
||||
entry_class_id);
|
||||
|
||||
buffer->delayed_data.push_back(
|
||||
std::move(edge_with_data_and_condition.first));
|
||||
|
||||
if (edge_with_data_and_condition.second)
|
||||
{
|
||||
buffer->conditionals.push_back(
|
||||
*edge_with_data_and_condition.second);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -826,6 +930,9 @@ void EdgeBasedGraphFactory::GenerateEdgeExpandedEdges(
|
||||
data.turn_indexes.begin(),
|
||||
data.turn_indexes.end());
|
||||
|
||||
conditionals.insert(
|
||||
conditionals.end(), buffer->conditionals.begin(), buffer->conditionals.end());
|
||||
|
||||
// Buffer writes to reduce syscall count
|
||||
if (turn_indexes_write_buffer.size() >= TURN_INDEX_WRITE_BUFFER_SIZE)
|
||||
{
|
||||
@@ -878,6 +985,20 @@ void EdgeBasedGraphFactory::GenerateEdgeExpandedEdges(
|
||||
}
|
||||
});
|
||||
|
||||
// re-hash conditionals to ocnnect to their respective edge-based edges. Due to the
|
||||
// ordering, we
|
||||
// do not really have a choice but to index the conditional penalties and walk over all
|
||||
// edge-based-edges to find the ID of the edge
|
||||
auto const indexed_conditionals = IndexConditionals(std::move(conditionals));
|
||||
{
|
||||
util::Log() << "Writing " << indexed_conditionals.size()
|
||||
<< " conditional turn penalties...";
|
||||
// write conditional turn penalties into the restrictions file
|
||||
storage::io::FileWriter writer(conditional_penalties_filename,
|
||||
storage::io::FileWriter::GenerateFingerprint);
|
||||
extractor::serialization::write(writer, indexed_conditionals);
|
||||
}
|
||||
|
||||
// write weight penalties per turn
|
||||
BOOST_ASSERT(turn_weight_penalties.size() == turn_duration_penalties.size());
|
||||
{
|
||||
@@ -917,11 +1038,36 @@ void EdgeBasedGraphFactory::GenerateEdgeExpandedEdges(
|
||||
util::Log() << " contains " << m_edge_based_edge_list.size() << " edges";
|
||||
util::Log() << " skips " << restricted_turns_counter << " turns, "
|
||||
"defined by "
|
||||
<< node_restriction_map.size() << " restrictions";
|
||||
<< node_restriction_map.Size() << " restrictions";
|
||||
util::Log() << " skips " << skipped_uturns_counter << " U turns";
|
||||
util::Log() << " skips " << skipped_barrier_turns_counter << " turns over barriers";
|
||||
}
|
||||
|
||||
std::vector<ConditionalTurnPenalty>
|
||||
EdgeBasedGraphFactory::IndexConditionals(std::vector<Conditional> &&conditionals) const
|
||||
{
|
||||
boost::unordered_multimap<std::pair<NodeID, NodeID>, ConditionalTurnPenalty *> index;
|
||||
|
||||
// build and index of all conditional restrictions
|
||||
for (auto &conditional : conditionals)
|
||||
index.insert(std::make_pair(std::make_pair(conditional.from_node, conditional.to_node),
|
||||
&conditional.penalty));
|
||||
|
||||
std::vector<ConditionalTurnPenalty> indexed_restrictions;
|
||||
|
||||
for (auto const &edge : m_edge_based_edge_list)
|
||||
{
|
||||
auto const range = index.equal_range(std::make_pair(edge.source, edge.target));
|
||||
for (auto itr = range.first; itr != range.second; ++itr)
|
||||
{
|
||||
itr->second->turn_offset = edge.data.turn_id;
|
||||
indexed_restrictions.push_back(*itr->second);
|
||||
}
|
||||
}
|
||||
|
||||
return indexed_restrictions;
|
||||
}
|
||||
|
||||
std::vector<util::guidance::BearingClass> EdgeBasedGraphFactory::GetBearingClasses() const
|
||||
{
|
||||
std::vector<util::guidance::BearingClass> result(bearing_class_hash.data.size());
|
||||
|
||||
@@ -126,7 +126,6 @@ ExtractionContainers::ExtractionContainers()
|
||||
*/
|
||||
void ExtractionContainers::PrepareData(ScriptingEnvironment &scripting_environment,
|
||||
const std::string &osrm_path,
|
||||
const std::string &restrictions_file_name,
|
||||
const std::string &name_file_name)
|
||||
{
|
||||
storage::io::FileWriter file_out(osrm_path, storage::io::FileWriter::GenerateFingerprint);
|
||||
@@ -139,7 +138,6 @@ void ExtractionContainers::PrepareData(ScriptingEnvironment &scripting_environme
|
||||
WriteEdges(file_out);
|
||||
|
||||
PrepareRestrictions();
|
||||
WriteConditionalRestrictions(restrictions_file_name);
|
||||
WriteCharData(name_file_name);
|
||||
}
|
||||
|
||||
@@ -616,33 +614,23 @@ void ExtractionContainers::WriteNodes(storage::io::FileWriter &file_out) const
|
||||
util::UnbufferedLog log;
|
||||
log << "Writing traffic light nodes ... ";
|
||||
TIMER_START(write_nodes);
|
||||
std::vector<NodeID> internal_traffic_lights;
|
||||
for (const auto osm_id : traffic_lights)
|
||||
std::vector<NodeID> internal_traffic_signals;
|
||||
for (const auto osm_id : traffic_signals)
|
||||
{
|
||||
const auto node_id = mapExternalToInternalNodeID(
|
||||
used_node_id_list.begin(), used_node_id_list.end(), osm_id);
|
||||
if (node_id != SPECIAL_NODEID)
|
||||
{
|
||||
internal_traffic_lights.push_back(node_id);
|
||||
internal_traffic_signals.push_back(node_id);
|
||||
}
|
||||
}
|
||||
storage::serialization::write(file_out, internal_traffic_lights);
|
||||
storage::serialization::write(file_out, internal_traffic_signals);
|
||||
log << "ok, after " << TIMER_SEC(write_nodes) << "s";
|
||||
}
|
||||
|
||||
util::Log() << "Processed " << max_internal_node_id << " nodes";
|
||||
}
|
||||
|
||||
void ExtractionContainers::WriteConditionalRestrictions(const std::string &path)
|
||||
{
|
||||
std::uint64_t written_restriction_count = conditional_turn_restrictions.size();
|
||||
storage::io::FileWriter restrictions_out_file(path,
|
||||
storage::io::FileWriter::GenerateFingerprint);
|
||||
serialization::write(restrictions_out_file, conditional_turn_restrictions);
|
||||
util::Log() << "number of conditional restrictions written to disk: "
|
||||
<< written_restriction_count;
|
||||
}
|
||||
|
||||
void ExtractionContainers::PrepareRestrictions()
|
||||
{
|
||||
|
||||
@@ -765,7 +753,7 @@ void ExtractionContainers::PrepareRestrictions()
|
||||
// translate the turn from one segment onto another into a node restriction (the ways can only
|
||||
// be connected at a single location)
|
||||
auto const get_node_restriction_from_OSM_ids = [&](
|
||||
auto const from_id, auto const to_id, const OSMNodeID via_node = MAX_OSM_NODEID) {
|
||||
auto const from_id, auto const to_id, const OSMNodeID via_node) {
|
||||
auto const from_segment_itr = referenced_ways.find(from_id);
|
||||
if (from_segment_itr->second.way_id != from_id)
|
||||
{
|
||||
@@ -792,9 +780,9 @@ void ExtractionContainers::PrepareRestrictions()
|
||||
auto const &external = external_type.AsWayRestriction();
|
||||
// check if we were able to resolve all the involved ways
|
||||
auto const from_restriction =
|
||||
get_node_restriction_from_OSM_ids(external.from, external.via);
|
||||
get_node_restriction_from_OSM_ids(external.from, external.via, MAX_OSM_NODEID);
|
||||
auto const to_restriction =
|
||||
get_node_restriction_from_OSM_ids(external.via, external.to);
|
||||
get_node_restriction_from_OSM_ids(external.via, external.to, MAX_OSM_NODEID);
|
||||
|
||||
// failed to translate either of the involved nodes?
|
||||
if (!from_restriction.Valid() || !to_restriction.Valid())
|
||||
@@ -837,7 +825,8 @@ void ExtractionContainers::PrepareRestrictions()
|
||||
const auto transform_into_internal_types =
|
||||
[&](const InputConditionalTurnRestriction &external_restriction) {
|
||||
// unconditional restriction
|
||||
if (external_restriction.condition.empty())
|
||||
if (external_restriction.condition.empty() &&
|
||||
external_restriction.Type() == RestrictionType::NODE_RESTRICTION)
|
||||
{
|
||||
TurnRestriction restriction;
|
||||
restriction.is_only = external_restriction.is_only;
|
||||
@@ -851,7 +840,9 @@ void ExtractionContainers::PrepareRestrictions()
|
||||
restriction.is_only = external_restriction.is_only;
|
||||
restriction.condition = std::move(external_restriction.condition);
|
||||
if (transform(external_restriction, restriction))
|
||||
{
|
||||
conditional_turn_restrictions.push_back(std::move(restriction));
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
|
||||
+46
-25
@@ -23,7 +23,7 @@
|
||||
#include "util/timing_util.hpp"
|
||||
|
||||
#include "extractor/compressed_edge_container.hpp"
|
||||
#include "extractor/restriction_map.hpp"
|
||||
#include "extractor/restriction_index.hpp"
|
||||
#include "extractor/way_restriction_map.hpp"
|
||||
#include "util/static_graph.hpp"
|
||||
#include "util/static_rtree.hpp"
|
||||
@@ -110,7 +110,8 @@ int Extractor::run(ScriptingEnvironment &scripting_environment)
|
||||
|
||||
guidance::LaneDescriptionMap turn_lane_map;
|
||||
std::vector<TurnRestriction> turn_restrictions;
|
||||
std::tie(turn_lane_map, turn_restrictions) =
|
||||
std::vector<ConditionalTurnRestriction> conditional_turn_restrictions;
|
||||
std::tie(turn_lane_map, turn_restrictions, conditional_turn_restrictions) =
|
||||
ParseOSMData(scripting_environment, number_of_threads);
|
||||
|
||||
// Transform the node-based graph that OSM is based on into an edge-based graph
|
||||
@@ -138,6 +139,7 @@ int Extractor::run(ScriptingEnvironment &scripting_environment)
|
||||
edge_based_edge_list,
|
||||
config.GetPath(".osrm.icd").string(),
|
||||
turn_restrictions,
|
||||
conditional_turn_restrictions,
|
||||
turn_lane_map);
|
||||
|
||||
auto number_of_node_based_nodes = graph_size.first;
|
||||
@@ -190,7 +192,9 @@ int Extractor::run(ScriptingEnvironment &scripting_environment)
|
||||
return 0;
|
||||
}
|
||||
|
||||
std::tuple<guidance::LaneDescriptionMap, std::vector<TurnRestriction>>
|
||||
std::tuple<guidance::LaneDescriptionMap,
|
||||
std::vector<TurnRestriction>,
|
||||
std::vector<ConditionalTurnRestriction>>
|
||||
Extractor::ParseOSMData(ScriptingEnvironment &scripting_environment,
|
||||
const unsigned number_of_threads)
|
||||
{
|
||||
@@ -333,7 +337,6 @@ Extractor::ParseOSMData(ScriptingEnvironment &scripting_environment,
|
||||
|
||||
extraction_containers.PrepareData(scripting_environment,
|
||||
config.GetPath(".osrm").string(),
|
||||
config.GetPath(".osrm.restrictions").string(),
|
||||
config.GetPath(".osrm.names").string());
|
||||
|
||||
auto profile_properties = scripting_environment.GetProfileProperties();
|
||||
@@ -344,7 +347,8 @@ Extractor::ParseOSMData(ScriptingEnvironment &scripting_environment,
|
||||
util::Log() << "extraction finished after " << TIMER_SEC(extracting) << "s";
|
||||
|
||||
return std::make_tuple(std::move(turn_lane_map),
|
||||
std::move(extraction_containers.unconditional_turn_restrictions));
|
||||
std::move(extraction_containers.unconditional_turn_restrictions),
|
||||
std::move(extraction_containers.conditional_turn_restrictions));
|
||||
}
|
||||
|
||||
void Extractor::FindComponents(unsigned max_edge_id,
|
||||
@@ -440,41 +444,45 @@ Extractor::LoadNodeBasedGraph(std::unordered_set<NodeID> &barriers,
|
||||
/**
|
||||
\brief Building an edge-expanded graph from node-based input and turn restrictions
|
||||
*/
|
||||
std::pair<std::size_t, EdgeID>
|
||||
Extractor::BuildEdgeExpandedGraph(ScriptingEnvironment &scripting_environment,
|
||||
std::vector<util::Coordinate> &coordinates,
|
||||
extractor::PackedOSMIDs &osm_node_ids,
|
||||
EdgeBasedNodeDataContainer &edge_based_nodes_container,
|
||||
std::vector<EdgeBasedNodeSegment> &edge_based_node_segments,
|
||||
std::vector<bool> &node_is_startpoint,
|
||||
std::vector<EdgeWeight> &edge_based_node_weights,
|
||||
util::DeallocatingVector<EdgeBasedEdge> &edge_based_edge_list,
|
||||
const std::string &intersection_class_output_file,
|
||||
std::vector<TurnRestriction> &turn_restrictions,
|
||||
guidance::LaneDescriptionMap &turn_lane_map)
|
||||
std::pair<std::size_t, EdgeID> Extractor::BuildEdgeExpandedGraph(
|
||||
ScriptingEnvironment &scripting_environment,
|
||||
std::vector<util::Coordinate> &coordinates,
|
||||
extractor::PackedOSMIDs &osm_node_ids,
|
||||
EdgeBasedNodeDataContainer &edge_based_nodes_container,
|
||||
std::vector<EdgeBasedNodeSegment> &edge_based_node_segments,
|
||||
std::vector<bool> &node_is_startpoint,
|
||||
std::vector<EdgeWeight> &edge_based_node_weights,
|
||||
util::DeallocatingVector<EdgeBasedEdge> &edge_based_edge_list,
|
||||
const std::string &intersection_class_output_file,
|
||||
std::vector<TurnRestriction> &turn_restrictions,
|
||||
std::vector<ConditionalTurnRestriction> &conditional_turn_restrictions,
|
||||
guidance::LaneDescriptionMap &turn_lane_map)
|
||||
{
|
||||
std::unordered_set<NodeID> barrier_nodes;
|
||||
std::unordered_set<NodeID> traffic_lights;
|
||||
std::unordered_set<NodeID> traffic_signals;
|
||||
|
||||
auto node_based_graph =
|
||||
LoadNodeBasedGraph(barrier_nodes, traffic_lights, coordinates, osm_node_ids);
|
||||
LoadNodeBasedGraph(barrier_nodes, traffic_signals, coordinates, osm_node_ids);
|
||||
|
||||
CompressedEdgeContainer compressed_edge_container;
|
||||
GraphCompressor graph_compressor;
|
||||
graph_compressor.Compress(barrier_nodes,
|
||||
traffic_lights,
|
||||
traffic_signals,
|
||||
scripting_environment,
|
||||
turn_restrictions,
|
||||
conditional_turn_restrictions,
|
||||
*node_based_graph,
|
||||
compressed_edge_container);
|
||||
|
||||
turn_restrictions = removeInvalidRestrictions(std::move(turn_restrictions), *node_based_graph);
|
||||
conditional_turn_restrictions =
|
||||
removeInvalidRestrictions(std::move(conditional_turn_restrictions), *node_based_graph);
|
||||
|
||||
util::NameTable name_table(config.GetPath(".osrm.names").string());
|
||||
|
||||
EdgeBasedGraphFactory edge_based_graph_factory(node_based_graph,
|
||||
compressed_edge_container,
|
||||
barrier_nodes,
|
||||
traffic_lights,
|
||||
traffic_signals,
|
||||
coordinates,
|
||||
osm_node_ids,
|
||||
scripting_environment.GetProfileProperties(),
|
||||
@@ -483,8 +491,20 @@ Extractor::BuildEdgeExpandedGraph(ScriptingEnvironment &scripting_environment,
|
||||
|
||||
const auto create_edge_based_edges = [&]() {
|
||||
// scoped to relase intermediate datastructures right after the call
|
||||
RestrictionMap via_node_restriction_map(turn_restrictions);
|
||||
WayRestrictionMap via_way_restriction_map(turn_restrictions);
|
||||
std::vector<TurnRestriction> node_restrictions;
|
||||
for (auto const &t : turn_restrictions)
|
||||
if (t.Type() == RestrictionType::NODE_RESTRICTION)
|
||||
node_restrictions.push_back(t);
|
||||
|
||||
std::vector<ConditionalTurnRestriction> conditional_node_restrictions;
|
||||
for (auto const &t : conditional_turn_restrictions)
|
||||
if (t.Type() == RestrictionType::NODE_RESTRICTION)
|
||||
conditional_node_restrictions.push_back(t);
|
||||
|
||||
RestrictionMap via_node_restriction_map(node_restrictions, IndexNodeByFromAndVia());
|
||||
WayRestrictionMap via_way_restriction_map(conditional_turn_restrictions);
|
||||
ConditionalRestrictionMap conditional_node_restriction_map(conditional_node_restrictions,
|
||||
IndexNodeByFromAndVia());
|
||||
turn_restrictions.clear();
|
||||
turn_restrictions.shrink_to_fit();
|
||||
|
||||
@@ -495,13 +515,14 @@ Extractor::BuildEdgeExpandedGraph(ScriptingEnvironment &scripting_environment,
|
||||
config.GetPath(".osrm.turn_duration_penalties").string(),
|
||||
config.GetPath(".osrm.turn_penalties_index").string(),
|
||||
config.GetPath(".osrm.cnbg_to_ebg").string(),
|
||||
config.GetPath(".osrm.restrictions").string(),
|
||||
via_node_restriction_map,
|
||||
conditional_node_restriction_map,
|
||||
via_way_restriction_map);
|
||||
return edge_based_graph_factory.GetNumberOfEdgeBasedNodes();
|
||||
};
|
||||
|
||||
const auto number_of_edge_based_nodes = create_edge_based_edges();
|
||||
|
||||
compressed_edge_container.PrintStatistics();
|
||||
|
||||
// The osrm-partition tool requires the compressed node based graph with an embedding.
|
||||
|
||||
@@ -69,7 +69,7 @@ void ExtractorCallbacks::ProcessNode(const osmium::Node &input_node,
|
||||
}
|
||||
if (result_node.traffic_lights)
|
||||
{
|
||||
external_memory.traffic_lights.push_back(id);
|
||||
external_memory.traffic_signals.push_back(id);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -1,6 +1,8 @@
|
||||
#include "extractor/graph_compressor.hpp"
|
||||
|
||||
#include "extractor/compressed_edge_container.hpp"
|
||||
#include "extractor/extraction_turn.hpp"
|
||||
#include "extractor/guidance/intersection.hpp"
|
||||
#include "extractor/restriction.hpp"
|
||||
#include "extractor/restriction_compressor.hpp"
|
||||
|
||||
@@ -18,16 +20,19 @@ namespace osrm
|
||||
namespace extractor
|
||||
{
|
||||
|
||||
void GraphCompressor::Compress(const std::unordered_set<NodeID> &barrier_nodes,
|
||||
const std::unordered_set<NodeID> &traffic_lights,
|
||||
std::vector<TurnRestriction> &turn_restrictions,
|
||||
util::NodeBasedDynamicGraph &graph,
|
||||
CompressedEdgeContainer &geometry_compressor)
|
||||
void GraphCompressor::Compress(
|
||||
const std::unordered_set<NodeID> &barrier_nodes,
|
||||
const std::unordered_set<NodeID> &traffic_signals,
|
||||
ScriptingEnvironment &scripting_environment,
|
||||
std::vector<TurnRestriction> &turn_restrictions,
|
||||
std::vector<ConditionalTurnRestriction> &conditional_turn_restrictions,
|
||||
util::NodeBasedDynamicGraph &graph,
|
||||
CompressedEdgeContainer &geometry_compressor)
|
||||
{
|
||||
const unsigned original_number_of_nodes = graph.GetNumberOfNodes();
|
||||
const unsigned original_number_of_edges = graph.GetNumberOfEdges();
|
||||
|
||||
RestrictionCompressor restriction_compressor(turn_restrictions);
|
||||
RestrictionCompressor restriction_compressor(turn_restrictions, conditional_turn_restrictions);
|
||||
|
||||
// we do not compress turn restrictions on degree two nodes. These nodes are usually used to
|
||||
// indicated `directed` barriers
|
||||
@@ -48,8 +53,13 @@ void GraphCompressor::Compress(const std::unordered_set<NodeID> &barrier_nodes,
|
||||
}
|
||||
};
|
||||
std::for_each(turn_restrictions.begin(), turn_restrictions.end(), remember_via_nodes);
|
||||
std::for_each(conditional_turn_restrictions.begin(),
|
||||
conditional_turn_restrictions.end(),
|
||||
remember_via_nodes);
|
||||
|
||||
{
|
||||
const auto weight_multiplier =
|
||||
scripting_environment.GetProfileProperties().GetWeightMultiplier();
|
||||
util::UnbufferedLog log;
|
||||
util::Percent progress(log, original_number_of_nodes);
|
||||
|
||||
@@ -184,13 +194,31 @@ void GraphCompressor::Compress(const std::unordered_set<NodeID> &barrier_nodes,
|
||||
graph.GetEdgeData(reverse_e2).lane_description_id = selectLaneID(
|
||||
rev_edge_data2.lane_description_id, rev_edge_data1.lane_description_id);
|
||||
|
||||
/*
|
||||
// Do not compress edge if it crosses a traffic signal.
|
||||
// This can't be done in CanCombineWith, becase we only store the
|
||||
// traffic signals in the `traffic_lights` list, which EdgeData
|
||||
// traffic signals in the `traffic signal` list, which EdgeData
|
||||
// doesn't have access to.
|
||||
const bool has_node_penalty = traffic_lights.find(node_v) != traffic_lights.end();
|
||||
*/
|
||||
const bool has_node_penalty = traffic_signals.find(node_v) != traffic_signals.end();
|
||||
boost::optional<EdgeDuration> node_duration_penalty = boost::none;
|
||||
boost::optional<EdgeWeight> node_weight_penalty = boost::none;
|
||||
if (has_node_penalty)
|
||||
continue;
|
||||
{
|
||||
// generate an artifical turn for the turn penalty generation
|
||||
ExtractionTurn extraction_turn(true);
|
||||
|
||||
extraction_turn.source_restricted = fwd_edge_data1.restricted;
|
||||
extraction_turn.target_restricted = fwd_edge_data2.restricted;
|
||||
|
||||
// we cannot handle this as node penalty, if it depends on turn direction
|
||||
if (extraction_turn.source_restricted != extraction_turn.target_restricted)
|
||||
continue;
|
||||
|
||||
scripting_environment.ProcessTurn(extraction_turn);
|
||||
node_duration_penalty = extraction_turn.duration * 10;
|
||||
node_weight_penalty = extraction_turn.weight * weight_multiplier;
|
||||
}
|
||||
|
||||
// Get weights before graph is modified
|
||||
const auto forward_weight1 = fwd_edge_data1.weight;
|
||||
@@ -217,6 +245,14 @@ void GraphCompressor::Compress(const std::unordered_set<NodeID> &barrier_nodes,
|
||||
graph.GetEdgeData(forward_e1).duration += forward_duration2;
|
||||
graph.GetEdgeData(reverse_e1).duration += reverse_duration2;
|
||||
|
||||
if (node_weight_penalty && node_duration_penalty)
|
||||
{
|
||||
graph.GetEdgeData(forward_e1).weight += *node_weight_penalty;
|
||||
graph.GetEdgeData(reverse_e1).weight += *node_weight_penalty;
|
||||
graph.GetEdgeData(forward_e1).duration += *node_duration_penalty;
|
||||
graph.GetEdgeData(reverse_e1).duration += *node_duration_penalty;
|
||||
}
|
||||
|
||||
// extend e1's to targets of e2's
|
||||
graph.SetTarget(forward_e1, node_w);
|
||||
graph.SetTarget(reverse_e1, node_u);
|
||||
@@ -236,7 +272,9 @@ void GraphCompressor::Compress(const std::unordered_set<NodeID> &barrier_nodes,
|
||||
forward_weight1,
|
||||
forward_weight2,
|
||||
forward_duration1,
|
||||
forward_duration2);
|
||||
forward_duration2,
|
||||
node_weight_penalty,
|
||||
node_duration_penalty);
|
||||
geometry_compressor.CompressEdge(reverse_e1,
|
||||
reverse_e2,
|
||||
node_v,
|
||||
@@ -244,7 +282,9 @@ void GraphCompressor::Compress(const std::unordered_set<NodeID> &barrier_nodes,
|
||||
reverse_weight1,
|
||||
reverse_weight2,
|
||||
reverse_duration1,
|
||||
reverse_duration2);
|
||||
reverse_duration2,
|
||||
node_weight_penalty,
|
||||
node_duration_penalty);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -122,15 +122,6 @@ util::Coordinate CoordinateExtractor::ExtractRepresentativeCoordinate(
|
||||
// coordinate set to add a small level of fault tolerance
|
||||
const constexpr double skipping_inaccuracies_distance = 2;
|
||||
|
||||
// fallback, mostly necessary for dead ends
|
||||
if (intersection_node == to_node)
|
||||
{
|
||||
const auto result = ExtractCoordinateAtLength(skipping_inaccuracies_distance, coordinates);
|
||||
// TODO: possibly re-enable with https://github.com/Project-OSRM/osrm-backend/issues/3470
|
||||
// BOOST_ASSERT(not_same_as_start(result));
|
||||
return result;
|
||||
}
|
||||
|
||||
const auto &turn_edge_data = node_based_graph.GetEdgeData(turn_edge);
|
||||
|
||||
// roundabouts, check early to avoid other costly checks
|
||||
@@ -377,14 +368,14 @@ util::Coordinate CoordinateExtractor::ExtractRepresentativeCoordinate(
|
||||
* destination lanes and the ones that performa a larger turn.
|
||||
*/
|
||||
coordinates = TrimCoordinatesToLength(
|
||||
std::move(coordinates), 2 * skipping_inaccuracies_distance, segment_distances);
|
||||
std::move(coordinates), 3 * skipping_inaccuracies_distance, segment_distances);
|
||||
BOOST_ASSERT(coordinates.size() >= 2);
|
||||
segment_distances.resize(coordinates.size());
|
||||
segment_distances.back() = util::coordinate_calculation::haversineDistance(
|
||||
*(coordinates.end() - 2), coordinates.back());
|
||||
const auto vector_head = coordinates.back();
|
||||
coordinates = TrimCoordinatesToLength(
|
||||
std::move(coordinates), skipping_inaccuracies_distance, segment_distances);
|
||||
std::move(coordinates), 2 * skipping_inaccuracies_distance, segment_distances);
|
||||
BOOST_ASSERT(coordinates.size() >= 2);
|
||||
const auto result =
|
||||
GetCorrectedCoordinate(turn_coordinate, coordinates.back(), vector_head);
|
||||
|
||||
@@ -236,8 +236,25 @@ IntersectionView IntersectionGenerator::TransformIntersectionShapeIntoView(
|
||||
{
|
||||
const auto node_at_intersection = node_based_graph.GetTarget(entering_via_edge);
|
||||
|
||||
// check if there is a single valid turn entering the current intersection
|
||||
const auto only_valid_turn = GetOnlyAllowedTurnIfExistent(previous_node, node_at_intersection);
|
||||
// request all turn restrictions
|
||||
auto const restrictions = restriction_map.Restrictions(previous_node, node_at_intersection);
|
||||
|
||||
// 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`
|
||||
const auto find_only_valid_turn = [&]() -> boost::optional<NodeID> {
|
||||
const auto itr = std::find_if(restrictions.first, restrictions.second, [](auto pair) {
|
||||
return pair.second->is_only;
|
||||
});
|
||||
if (itr != restrictions.second)
|
||||
return itr->second->AsNodeRestriction().to;
|
||||
else
|
||||
return boost::none;
|
||||
};
|
||||
|
||||
const auto only_valid_turn = find_only_valid_turn();
|
||||
|
||||
// barriers change our behaviour regarding u-turns
|
||||
const bool is_barrier_node = barrier_nodes.find(node_at_intersection) != barrier_nodes.end();
|
||||
@@ -258,12 +275,14 @@ IntersectionView IntersectionGenerator::TransformIntersectionShapeIntoView(
|
||||
|
||||
const auto is_restricted = [&](const NodeID destination) {
|
||||
// check if we have a dedicated destination
|
||||
if (only_valid_turn && *only_valid_turn != destination)
|
||||
return true;
|
||||
if (only_valid_turn)
|
||||
return *only_valid_turn != destination;
|
||||
|
||||
// not explicitly forbidden
|
||||
return restriction_map.CheckIfTurnIsRestricted(
|
||||
previous_node, node_at_intersection, destination);
|
||||
// check if explicitly forbidden
|
||||
return restrictions.second !=
|
||||
std::find_if(restrictions.first, restrictions.second, [&](const auto &restriction) {
|
||||
return restriction.second->AsNodeRestriction().to == destination;
|
||||
});
|
||||
};
|
||||
|
||||
const auto is_allowed_turn = [&](const IntersectionShapeData &road) {
|
||||
@@ -396,21 +415,6 @@ IntersectionView IntersectionGenerator::TransformIntersectionShapeIntoView(
|
||||
return intersection_view;
|
||||
}
|
||||
|
||||
boost::optional<NodeID>
|
||||
IntersectionGenerator::GetOnlyAllowedTurnIfExistent(const NodeID coming_from_node,
|
||||
const NodeID node_at_intersection) const
|
||||
{
|
||||
// If only restrictions refer to invalid ways somewhere far away, we rather ignore the
|
||||
// restriction than to not route over the intersection at all.
|
||||
const auto only_restriction_to_node =
|
||||
restriction_map.CheckForEmanatingIsOnlyTurn(coming_from_node, node_at_intersection);
|
||||
if (only_restriction_to_node != SPECIAL_NODEID)
|
||||
return only_restriction_to_node;
|
||||
|
||||
// Ignore broken only restrictions.
|
||||
return boost::none;
|
||||
}
|
||||
|
||||
const CoordinateExtractor &IntersectionGenerator::GetCoordinateExtractor() const
|
||||
{
|
||||
return coordinate_extractor;
|
||||
|
||||
@@ -263,8 +263,9 @@ operator()(const NodeID /*nid*/, const EdgeID source_edge_id, Intersection inter
|
||||
if (!allSameMode(source_edge_id, sliproad.eid, find_valid(target_intersection)->eid))
|
||||
continue;
|
||||
|
||||
// Constrain the Sliproad's target to sliproad, outgoing, incoming from main intersection
|
||||
if (target_intersection.size() != 3)
|
||||
// Constrain the sliproad's target intersection to 1 or 2 sliproads, outgoing road
|
||||
// and incoming one from the main intersection
|
||||
if (target_intersection.size() < 3 || target_intersection.size() > 4)
|
||||
{
|
||||
continue;
|
||||
}
|
||||
@@ -279,6 +280,51 @@ operator()(const NodeID /*nid*/, const EdgeID source_edge_id, Intersection inter
|
||||
continue;
|
||||
}
|
||||
|
||||
if (target_intersection.size() == 4)
|
||||
{
|
||||
// Handle target intersections at `d` with 4 roads
|
||||
//
|
||||
// | `main_road_intersection` is intersection at `c`
|
||||
// v
|
||||
// a ... b .... c .... e <- fo
|
||||
// ` . '
|
||||
// ` . '
|
||||
// ` . '
|
||||
// d < `target_intersection` is intersection at `d`
|
||||
// |
|
||||
// Conditions for road `bd` to be a sliproad:
|
||||
// - target_intersection at `d` has 4 roads
|
||||
// - main_road_intersection at `c` has at least 3 roads
|
||||
// - target nodes of `db` and `cd` roads is the same node `d`
|
||||
// - target nodes of `ce` and `de` roads is the same node `e`
|
||||
// - angle `bde` is sharp
|
||||
|
||||
// Check `c` has at least 3 roads at `c` and roads `bd` and `cd` share the node `d`
|
||||
if (main_road_intersection->intersection.size() < 3 ||
|
||||
sliproad_edge_target != node_based_graph.GetTarget(crossing_road.eid))
|
||||
{
|
||||
continue;
|
||||
}
|
||||
|
||||
// Find a road at `d` that shares the same node `e` with `ce` and ∠ `bde` is sharp
|
||||
auto next_to_crossing_idx =
|
||||
is_left_sliproad_turn ? main_road_intersection->intersection.size() - 2 : 2;
|
||||
auto next_to_crossing_road = main_road_intersection->intersection[next_to_crossing_idx];
|
||||
auto next_to_crossing_node = node_based_graph.GetTarget(next_to_crossing_road.eid);
|
||||
auto found_common_node = std::find_if(
|
||||
begin(target_intersection), end(target_intersection), [&](const auto &road) {
|
||||
if (next_to_crossing_node == node_based_graph.GetTarget(road.eid))
|
||||
{
|
||||
auto direction = getTurnDirection(road.angle);
|
||||
return direction == DirectionModifier::SharpRight ||
|
||||
direction == DirectionModifier::SharpLeft;
|
||||
}
|
||||
return false;
|
||||
});
|
||||
if (found_common_node == target_intersection.end())
|
||||
continue;
|
||||
}
|
||||
|
||||
// If the sliproad candidate is a through street, we cannot handle it as a sliproad.
|
||||
if (isThroughStreet(sliproad_edge, target_intersection))
|
||||
{
|
||||
@@ -386,7 +432,9 @@ operator()(const NodeID /*nid*/, const EdgeID source_edge_id, Intersection inter
|
||||
continue;
|
||||
}
|
||||
|
||||
if (deviation_from_straight > perpendicular_angle)
|
||||
// Check sliproads with skew main intersections
|
||||
if (deviation_from_straight > perpendicular_angle &&
|
||||
!node_based_graph.GetEdgeData(sliproad.eid).road_classification.IsLinkClass())
|
||||
{
|
||||
continue;
|
||||
}
|
||||
|
||||
@@ -391,6 +391,7 @@ Intersection TurnHandler::handleComplexTurn(const EdgeID via_edge, Intersection
|
||||
{
|
||||
assignTrivialTurns(via_edge, intersection, 1, intersection.size());
|
||||
}
|
||||
|
||||
return intersection;
|
||||
}
|
||||
|
||||
@@ -744,7 +745,7 @@ void TurnHandler::handleDistinctConflict(const EdgeID via_edge,
|
||||
right.instruction = {right_type, DirectionModifier::Right};
|
||||
return;
|
||||
}
|
||||
// Two Right Turns
|
||||
// Two Left Turns
|
||||
if (angularDeviation(left.angle, 270) < MAXIMAL_ALLOWED_NO_TURN_DEVIATION)
|
||||
{
|
||||
// Keep left perfect, shift right
|
||||
@@ -773,17 +774,18 @@ void TurnHandler::handleDistinctConflict(const EdgeID via_edge,
|
||||
return;
|
||||
}
|
||||
|
||||
if (getTurnDirection(left.angle) == DirectionModifier::Right)
|
||||
// turn to the right
|
||||
if (getTurnDirection(left.angle) <= 180)
|
||||
{
|
||||
if (angularDeviation(left.angle, 85) >= angularDeviation(right.angle, 85))
|
||||
{
|
||||
left.instruction = {left_type, DirectionModifier::Right};
|
||||
right.instruction = {right_type, DirectionModifier::SharpRight};
|
||||
left.instruction = {left_type, DirectionModifier::SlightRight};
|
||||
right.instruction = {right_type, DirectionModifier::Right};
|
||||
}
|
||||
else
|
||||
{
|
||||
left.instruction = {left_type, DirectionModifier::SlightRight};
|
||||
right.instruction = {right_type, DirectionModifier::Right};
|
||||
left.instruction = {left_type, DirectionModifier::Right};
|
||||
right.instruction = {right_type, DirectionModifier::SharpRight};
|
||||
}
|
||||
}
|
||||
else
|
||||
|
||||
@@ -10,7 +10,9 @@ namespace osrm
|
||||
namespace extractor
|
||||
{
|
||||
|
||||
RestrictionCompressor::RestrictionCompressor(std::vector<TurnRestriction> &restrictions)
|
||||
RestrictionCompressor::RestrictionCompressor(
|
||||
std::vector<TurnRestriction> &restrictions,
|
||||
std::vector<ConditionalTurnRestriction> &conditional_turn_restrictions)
|
||||
{
|
||||
// add a node restriction ptr to the starts/ends maps, needs to be a reference!
|
||||
auto index = [&](auto &element) {
|
||||
@@ -35,6 +37,9 @@ RestrictionCompressor::RestrictionCompressor(std::vector<TurnRestriction> &restr
|
||||
|
||||
// add all restrictions as their respective startend pointers
|
||||
std::for_each(restrictions.begin(), restrictions.end(), index_starts_and_ends);
|
||||
std::for_each(conditional_turn_restrictions.begin(),
|
||||
conditional_turn_restrictions.end(),
|
||||
index_starts_and_ends);
|
||||
}
|
||||
|
||||
void RestrictionCompressor::Compress(const NodeID from, const NodeID via, const NodeID to)
|
||||
|
||||
@@ -10,8 +10,8 @@ namespace osrm
|
||||
namespace extractor
|
||||
{
|
||||
|
||||
std::vector<TurnRestriction>
|
||||
removeInvalidRestrictions(std::vector<TurnRestriction> restrictions,
|
||||
std::vector<ConditionalTurnRestriction>
|
||||
removeInvalidRestrictions(std::vector<ConditionalTurnRestriction> restrictions,
|
||||
const util::NodeBasedDynamicGraph &node_based_graph)
|
||||
{
|
||||
// definition of what we presume to be a valid via-node restriction
|
||||
|
||||
@@ -1,138 +0,0 @@
|
||||
#include "extractor/restriction_map.hpp"
|
||||
|
||||
#include <boost/assert.hpp>
|
||||
|
||||
namespace osrm
|
||||
{
|
||||
namespace extractor
|
||||
{
|
||||
|
||||
RestrictionMap::RestrictionMap(const std::vector<TurnRestriction> &restriction_list) : m_count(0)
|
||||
{
|
||||
// decompose restriction consisting of a start, via and end node into a
|
||||
// a pair of starting edge and a list of all end nodes
|
||||
for (auto &restriction : restriction_list)
|
||||
{
|
||||
// only handle node restrictions here
|
||||
if (restriction.Type() == RestrictionType::WAY_RESTRICTION)
|
||||
continue;
|
||||
|
||||
const auto &node_restriction = restriction.AsNodeRestriction();
|
||||
BOOST_ASSERT(node_restriction.Valid());
|
||||
// This downcasting is OK because when this is called, the node IDs have been
|
||||
// renumbered into internal values, which should be well under 2^32
|
||||
// This will be a problem if we have more than 2^32 actual restrictions
|
||||
BOOST_ASSERT(node_restriction.from < std::numeric_limits<NodeID>::max());
|
||||
BOOST_ASSERT(node_restriction.via < std::numeric_limits<NodeID>::max());
|
||||
m_restriction_start_nodes.insert(node_restriction.from);
|
||||
m_no_turn_via_node_set.insert(node_restriction.via);
|
||||
|
||||
// This explicit downcasting is also OK for the same reason.
|
||||
RestrictionSource restriction_source = {static_cast<NodeID>(node_restriction.from),
|
||||
static_cast<NodeID>(node_restriction.via)};
|
||||
|
||||
std::size_t index;
|
||||
auto restriction_iter = m_restriction_map.find(restriction_source);
|
||||
if (restriction_iter == m_restriction_map.end())
|
||||
{
|
||||
index = m_restriction_bucket_list.size();
|
||||
m_restriction_bucket_list.resize(index + 1);
|
||||
m_restriction_map.emplace(restriction_source, index);
|
||||
}
|
||||
else
|
||||
{
|
||||
index = restriction_iter->second;
|
||||
// Map already contains an is_only_*-restriction
|
||||
if (m_restriction_bucket_list.at(index).begin()->is_only)
|
||||
{
|
||||
continue;
|
||||
}
|
||||
else if (restriction.is_only)
|
||||
{
|
||||
// We are going to insert an is_only_*-restriction. There can be only one.
|
||||
m_count -= m_restriction_bucket_list.at(index).size();
|
||||
m_restriction_bucket_list.at(index).clear();
|
||||
}
|
||||
}
|
||||
++m_count;
|
||||
m_restriction_bucket_list.at(index).emplace_back(node_restriction.to, restriction.is_only);
|
||||
}
|
||||
}
|
||||
|
||||
bool RestrictionMap::IsViaNode(const NodeID node) const
|
||||
{
|
||||
return m_no_turn_via_node_set.find(node) != m_no_turn_via_node_set.end();
|
||||
}
|
||||
|
||||
// Check if edge (u, v) is the start of any turn restriction.
|
||||
// If so returns id of first target node.
|
||||
NodeID RestrictionMap::CheckForEmanatingIsOnlyTurn(const NodeID node_u, const NodeID node_v) const
|
||||
{
|
||||
BOOST_ASSERT(node_u != SPECIAL_NODEID);
|
||||
BOOST_ASSERT(node_v != SPECIAL_NODEID);
|
||||
|
||||
if (!IsSourceNode(node_u))
|
||||
{
|
||||
return SPECIAL_NODEID;
|
||||
}
|
||||
|
||||
const auto restriction_iter = m_restriction_map.find({node_u, node_v});
|
||||
if (restriction_iter != m_restriction_map.end())
|
||||
{
|
||||
const unsigned index = restriction_iter->second;
|
||||
const auto &bucket = m_restriction_bucket_list.at(index);
|
||||
for (const RestrictionTarget &restriction_target : bucket)
|
||||
{
|
||||
if (restriction_target.is_only)
|
||||
{
|
||||
return restriction_target.target_node;
|
||||
}
|
||||
}
|
||||
}
|
||||
return SPECIAL_NODEID;
|
||||
}
|
||||
|
||||
// Checks if turn <u,v,w> is actually a turn restriction.
|
||||
bool RestrictionMap::CheckIfTurnIsRestricted(const NodeID node_u,
|
||||
const NodeID node_v,
|
||||
const NodeID node_w) const
|
||||
{
|
||||
BOOST_ASSERT(node_u != SPECIAL_NODEID);
|
||||
BOOST_ASSERT(node_v != SPECIAL_NODEID);
|
||||
BOOST_ASSERT(node_w != SPECIAL_NODEID);
|
||||
|
||||
if (!IsSourceNode(node_u))
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
const auto restriction_iter = m_restriction_map.find({node_u, node_v});
|
||||
if (restriction_iter == m_restriction_map.end())
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
const unsigned index = restriction_iter->second;
|
||||
const auto &bucket = m_restriction_bucket_list.at(index);
|
||||
|
||||
for (const RestrictionTarget &restriction_target : bucket)
|
||||
{
|
||||
if (node_w == restriction_target.target_node && // target found
|
||||
!restriction_target.is_only) // and not an only_-restr.
|
||||
{
|
||||
return true;
|
||||
}
|
||||
// We could be tempted to check for `only` restrictions here as well. However, that check is
|
||||
// actually perfomed in intersection generation where we can also verify if the only
|
||||
// restriction is valid at all.
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
// check of node is the start of any restriction
|
||||
bool RestrictionMap::IsSourceNode(const NodeID node) const
|
||||
{
|
||||
return m_restriction_start_nodes.find(node) != m_restriction_start_nodes.end();
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -128,7 +128,7 @@ RestrictionParser::TryParse(const osmium::Relation &relation) const
|
||||
restriction_container.is_only = is_only_restriction;
|
||||
|
||||
boost::optional<std::uint64_t> from = boost::none, via = boost::none, to = boost::none;
|
||||
bool is_node_restriction;
|
||||
bool is_node_restriction = true;
|
||||
|
||||
for (const auto &member : relation.members())
|
||||
{
|
||||
|
||||
@@ -396,8 +396,12 @@ void Sol2ScriptingEnvironment::InitContext(LuaScriptingContext &context)
|
||||
"target_restricted",
|
||||
&ExtractionTurn::target_restricted);
|
||||
|
||||
// Keep in mind .location is undefined since we're not using libosmium's location cache
|
||||
context.state.new_usertype<osmium::NodeRef>("NodeRef", "id", &osmium::NodeRef::ref);
|
||||
// Keep in mind .location is available only if .pbf is preprocessed to set the location with the
|
||||
// ref using osmium command "osmium add-locations-to-ways"
|
||||
context.state.new_usertype<osmium::NodeRef>(
|
||||
"NodeRef", "id", &osmium::NodeRef::ref, "location", [](const osmium::NodeRef &nref) {
|
||||
return nref.location();
|
||||
});
|
||||
|
||||
context.state.new_usertype<InternalExtractorEdge>("EdgeSource",
|
||||
"source_coordinate",
|
||||
|
||||
@@ -1,6 +1,7 @@
|
||||
#include "extractor/way_restriction_map.hpp"
|
||||
#include "util/for_each_pair.hpp"
|
||||
|
||||
#include <functional>
|
||||
#include <iterator>
|
||||
#include <tuple>
|
||||
#include <utility>
|
||||
@@ -28,12 +29,46 @@ struct FindViaWay
|
||||
}
|
||||
};
|
||||
|
||||
} // namespace
|
||||
|
||||
WayRestrictionMap::WayRestrictionMap(const std::vector<TurnRestriction> &turn_restrictions)
|
||||
template <typename restriction_type> auto asDuplicatedNode(const restriction_type &restriction)
|
||||
{
|
||||
// get all way restrictions
|
||||
const auto extract_restrictions = [this](const auto &turn_restriction) {
|
||||
auto &way = restriction.AsWayRestriction();
|
||||
// group restrictions by the via-way. On same via-ways group by from
|
||||
return std::tie(way.in_restriction.via, way.out_restriction.via, way.in_restriction.from);
|
||||
};
|
||||
|
||||
template <typename restriction_type> struct CompareByDuplicatedNode
|
||||
{
|
||||
bool operator()(const ConditionalTurnRestriction &lhs, const ConditionalTurnRestriction &rhs)
|
||||
{
|
||||
if (asDuplicatedNode(lhs) < asDuplicatedNode(rhs))
|
||||
{
|
||||
return true;
|
||||
}
|
||||
else if (asDuplicatedNode(rhs) < asDuplicatedNode(lhs))
|
||||
{
|
||||
return false;
|
||||
}
|
||||
else
|
||||
{
|
||||
const auto lhs_to = lhs.AsWayRestriction().out_restriction.to;
|
||||
const auto rhs_to = rhs.AsWayRestriction().out_restriction.to;
|
||||
|
||||
const bool has_conditions_lhs = !lhs.condition.empty();
|
||||
const bool has_conditions_rhs = !rhs.condition.empty();
|
||||
|
||||
return std::tie(lhs_to, lhs.is_only, has_conditions_lhs) <
|
||||
std::tie(rhs_to, rhs.is_only, has_conditions_rhs);
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
template <typename restriction_type>
|
||||
std::vector<restriction_type>
|
||||
extractRestrictions(const std::vector<restriction_type> &turn_restrictions)
|
||||
{
|
||||
std::vector<restriction_type> result;
|
||||
for (const auto &turn_restriction : turn_restrictions)
|
||||
{
|
||||
if (turn_restriction.Type() == RestrictionType::WAY_RESTRICTION)
|
||||
{
|
||||
const auto &way = turn_restriction.AsWayRestriction();
|
||||
@@ -41,32 +76,32 @@ WayRestrictionMap::WayRestrictionMap(const std::vector<TurnRestriction> &turn_re
|
||||
// so far we can only handle restrictions that are not interrupted
|
||||
if (way.in_restriction.via == way.out_restriction.from &&
|
||||
way.in_restriction.to == way.out_restriction.via)
|
||||
restriction_data.push_back(turn_restriction);
|
||||
result.push_back(turn_restriction);
|
||||
}
|
||||
};
|
||||
std::for_each(turn_restrictions.begin(), turn_restrictions.end(), extract_restrictions);
|
||||
}
|
||||
std::sort(result.begin(), result.end(), CompareByDuplicatedNode<restriction_type>());
|
||||
auto new_end = std::unique(result.begin(), result.end());
|
||||
result.erase(new_end, result.end());
|
||||
return result;
|
||||
}
|
||||
|
||||
const auto as_duplicated_node = [](auto const &restriction) {
|
||||
auto &way = restriction.AsWayRestriction();
|
||||
// group restrictions by the via-way. On same via-ways group by from
|
||||
return std::tie(way.in_restriction.via, way.out_restriction.via, way.in_restriction.from);
|
||||
};
|
||||
|
||||
const auto by_duplicated_node = [&](auto const &lhs, auto const &rhs) {
|
||||
return as_duplicated_node(lhs) < as_duplicated_node(rhs);
|
||||
};
|
||||
|
||||
std::sort(restriction_data.begin(), restriction_data.end(), by_duplicated_node);
|
||||
|
||||
// map all way restrictions into access containers
|
||||
for (RestrictionID index = 0; index < restriction_data.size(); ++index)
|
||||
template <typename restriction_type> struct ByInFromAndVia
|
||||
{
|
||||
std::pair<NodeID, NodeID> operator()(const restriction_type &restriction)
|
||||
{
|
||||
const auto &restriction = restriction_data[index];
|
||||
const auto &way = restriction.AsWayRestriction();
|
||||
restriction_starts.insert(
|
||||
std::make_pair(std::make_pair(way.in_restriction.from, way.in_restriction.via), index));
|
||||
};
|
||||
return std::make_pair(way.in_restriction.from, way.in_restriction.via);
|
||||
}
|
||||
};
|
||||
|
||||
} // namespace
|
||||
|
||||
// get all way restrictions
|
||||
WayRestrictionMap::WayRestrictionMap(
|
||||
const std::vector<ConditionalTurnRestriction> &turn_restrictions_)
|
||||
: restriction_data(extractRestrictions(turn_restrictions_)),
|
||||
restriction_starts(restriction_data, ByInFromAndVia<ConditionalTurnRestriction>())
|
||||
{
|
||||
std::size_t offset = 1;
|
||||
// the first group starts at 0
|
||||
if (!restriction_data.empty())
|
||||
@@ -74,8 +109,10 @@ WayRestrictionMap::WayRestrictionMap(const std::vector<TurnRestriction> &turn_re
|
||||
|
||||
auto const add_offset_on_new_groups = [&](auto const &lhs, auto const &rhs) {
|
||||
BOOST_ASSERT(rhs == restriction_data[offset]);
|
||||
BOOST_ASSERT(lhs.Type() == RestrictionType::WAY_RESTRICTION);
|
||||
BOOST_ASSERT(rhs.Type() == RestrictionType::WAY_RESTRICTION);
|
||||
// add a new lower bound for rhs
|
||||
if (as_duplicated_node(lhs) != as_duplicated_node(rhs))
|
||||
if (asDuplicatedNode(lhs) != asDuplicatedNode(rhs))
|
||||
duplicated_node_groups.push_back(offset);
|
||||
++offset;
|
||||
};
|
||||
@@ -115,7 +152,7 @@ DuplicatedNodeID WayRestrictionMap::AsDuplicatedNodeID(const RestrictionID restr
|
||||
return distance_to_upper_bound - 1;
|
||||
}
|
||||
|
||||
util::range<DuplicatedNodeID> WayRestrictionMap::DuplicatedNodeIDs(const NodeID from,
|
||||
std::vector<DuplicatedNodeID> WayRestrictionMap::DuplicatedNodeIDs(const NodeID from,
|
||||
const NodeID to) const
|
||||
{
|
||||
const auto duplicated_node_range_itr = std::equal_range(
|
||||
@@ -125,9 +162,13 @@ util::range<DuplicatedNodeID> WayRestrictionMap::DuplicatedNodeIDs(const NodeID
|
||||
return std::distance(restriction_data.begin(), itr);
|
||||
};
|
||||
|
||||
return util::irange<DuplicatedNodeID>(
|
||||
AsDuplicatedNodeID(as_restriction_id(duplicated_node_range_itr.first)),
|
||||
AsDuplicatedNodeID(as_restriction_id(duplicated_node_range_itr.second)));
|
||||
auto first = AsDuplicatedNodeID(as_restriction_id(duplicated_node_range_itr.first));
|
||||
auto end = AsDuplicatedNodeID(as_restriction_id(duplicated_node_range_itr.second));
|
||||
|
||||
std::vector<DuplicatedNodeID> result(end - first);
|
||||
std::iota(result.begin(), result.end(), first);
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
bool WayRestrictionMap::IsRestricted(DuplicatedNodeID duplicated_node, const NodeID to) const
|
||||
@@ -138,6 +179,7 @@ bool WayRestrictionMap::IsRestricted(DuplicatedNodeID duplicated_node, const Nod
|
||||
restriction_index != duplicated_node_groups[duplicated_node + 1];
|
||||
++restriction_index)
|
||||
{
|
||||
BOOST_ASSERT(restriction_index < restriction_data.size());
|
||||
const auto &restriction = restriction_data[restriction_index];
|
||||
const auto &way = restriction.AsWayRestriction();
|
||||
|
||||
@@ -149,6 +191,32 @@ bool WayRestrictionMap::IsRestricted(DuplicatedNodeID duplicated_node, const Nod
|
||||
return false;
|
||||
}
|
||||
|
||||
ConditionalTurnRestriction const &
|
||||
WayRestrictionMap::GetRestriction(DuplicatedNodeID duplicated_node, const NodeID to) const
|
||||
{
|
||||
// loop over all restrictions associated with the node. Mark as restricted based on
|
||||
// is_only/restricted targets
|
||||
for (RestrictionID restriction_index = duplicated_node_groups[duplicated_node];
|
||||
restriction_index != duplicated_node_groups[duplicated_node + 1];
|
||||
++restriction_index)
|
||||
{
|
||||
BOOST_ASSERT(restriction_index < restriction_data.size());
|
||||
const auto &restriction = restriction_data[restriction_index];
|
||||
const auto &way = restriction.AsWayRestriction();
|
||||
|
||||
if (restriction.is_only && (way.out_restriction.to != to))
|
||||
{
|
||||
return restriction;
|
||||
}
|
||||
else if (!restriction.is_only && (to == way.out_restriction.to))
|
||||
{
|
||||
return restriction;
|
||||
}
|
||||
}
|
||||
throw("Asking for the restriction of an unrestricted turn. Check with `IsRestricted` before "
|
||||
"calling GetRestriction");
|
||||
}
|
||||
|
||||
std::vector<WayRestrictionMap::ViaWay> WayRestrictionMap::DuplicatedNodeRepresentatives() const
|
||||
{
|
||||
std::vector<ViaWay> result;
|
||||
@@ -169,19 +237,19 @@ NodeID WayRestrictionMap::RemapIfRestricted(const NodeID edge_based_node,
|
||||
const NodeID node_based_to,
|
||||
const NodeID number_of_edge_based_nodes) const
|
||||
{
|
||||
auto range = restriction_starts.equal_range(std::make_pair(node_based_from, node_based_via));
|
||||
auto range = restriction_starts.Restrictions(node_based_from, node_based_via);
|
||||
|
||||
// returns true if the ID saved in an iterator belongs to a turn restriction that references
|
||||
// node_based_to as destination of the `in_restriction`
|
||||
const auto restriction_targets_to = [node_based_to, this](const auto &pair) {
|
||||
return restriction_data[pair.second].AsWayRestriction().in_restriction.to == node_based_to;
|
||||
return pair.second->AsWayRestriction().in_restriction.to == node_based_to;
|
||||
};
|
||||
const auto itr = std::find_if(range.first, range.second, restriction_targets_to);
|
||||
|
||||
// in case we found a matching restriction, we can remap the edge_based_node
|
||||
if (itr != range.second)
|
||||
return number_of_edge_based_nodes - NumberOfDuplicatedNodes() +
|
||||
AsDuplicatedNodeID(itr->second);
|
||||
AsDuplicatedNodeID(itr->second - &restriction_data[0]);
|
||||
else
|
||||
return edge_based_node;
|
||||
}
|
||||
|
||||
@@ -72,6 +72,12 @@ NAN_MODULE_INIT(Engine::Init)
|
||||
* @param {Boolean} [options.shared_memory] Connects to the persistent shared memory datastore.
|
||||
* This requires you to run `osrm-datastore` prior to creating an `OSRM` object.
|
||||
* @param {String} [options.path] The path to the `.osrm` files. This is mutually exclusive with setting {options.shared_memory} to true.
|
||||
* @param {Number} [options.max_locations_trip] Max. locations supported in trip query (default: unlimited).
|
||||
* @param {Number} [options.max_locations_viaroute] Max. locations supported in viaroute query (default: unlimited).
|
||||
* @param {Number} [options.max_locations_distance_table] Max. locations supported in distance table query (default: unlimited).
|
||||
* @param {Number} [options.max_locations_map_matching] Max. locations supported in map-matching query (default: unlimited).
|
||||
* @param {Number} [options.max_results_nearest] Max. results supported in nearest query (default: unlimited).
|
||||
* @param {Number} [options.max_alternatives] Max.number of alternatives supported in alternative routes query (default: 3).
|
||||
*
|
||||
* @class OSRM
|
||||
*
|
||||
@@ -193,6 +199,7 @@ inline void async(const Nan::FunctionCallbackInfo<v8::Value> &info,
|
||||
* @param {String} [options.geometries=polyline] Returned route geometry format (influences overview and per step). Can also be `geojson`.
|
||||
* @param {String} [options.overview=simplified] Add overview geometry either `full`, `simplified` according to highest zoom level it could be display on, or not at all (`false`).
|
||||
* @param {Boolean} [options.continue_straight] 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.
|
||||
* @param {Array} [options.approaches] Keep waypoints on curb side. Can be `null` (unrestricted, default) or `curb`.
|
||||
* `null`/`true`/`false`
|
||||
* @param {Function} callback
|
||||
*
|
||||
@@ -228,6 +235,7 @@ NAN_METHOD(Engine::route) //
|
||||
* @param {Array} [options.hints] Hints for the coordinate snapping. Array of base64 encoded strings.
|
||||
* @param {Number} [options.number=1] Number of nearest segments that should be returned.
|
||||
* Must be an integer greater than or equal to `1`.
|
||||
* @param {Array} [options.approaches] Keep waypoints on curb side. Can be `null` (unrestricted, default) or `curb`.
|
||||
* @param {Function} callback
|
||||
*
|
||||
* @returns {Object} containing `waypoints`.
|
||||
@@ -269,6 +277,7 @@ NAN_METHOD(Engine::nearest) //
|
||||
* location with given index as source. Default is to use all.
|
||||
* @param {Array} [options.destinations] An array of `index` elements (`0 <= integer <
|
||||
* #coordinates`) to use location with given index as destination. Default is to use all.
|
||||
* @param {Array} [options.approaches] Keep waypoints on curb side. Can be `null` (unrestricted, default) or `curb`.
|
||||
* @param {Function} callback
|
||||
*
|
||||
* @returns {Object} containing `durations`, `sources`, and `destinations`.
|
||||
@@ -350,6 +359,9 @@ NAN_METHOD(Engine::tile)
|
||||
* @param {String} [options.overview=simplified] Add overview geometry either `full`, `simplified` according to highest zoom level it could be display on, or not at all (`false`).
|
||||
* @param {Array<Number>} [options.timestamps] Timestamp of the input location (integers, UNIX-like timestamp).
|
||||
* @param {Array} [options.radiuses] Standard deviation of GPS precision used for map matching. If applicable use GPS accuracy. Can be `null` for default value `5` meters or `double >= 0`.
|
||||
* @param {String} [options.gaps] Allows the input track splitting based on huge timestamp gaps between points. Either `split` or `ignore` (optional, default `split`).
|
||||
* @param {Boolean} [options.tidy] Allows the input track modification to obtain better matching quality for noisy tracks (optional, default `false`).
|
||||
*
|
||||
* @param {Function} callback
|
||||
*
|
||||
* @returns {Object} containing `tracepoints` and `matchings`.
|
||||
@@ -418,6 +430,7 @@ NAN_METHOD(Engine::match) //
|
||||
* @param {Boolean} [options.roundtrip=true] Return route is a roundtrip.
|
||||
* @param {String} [options.source=any] Return route starts at `any` or `first` coordinate.
|
||||
* @param {String} [options.destination=any] Return route ends at `any` or `last` coordinate.
|
||||
* @param {Array} [options.approaches] Keep waypoints on curb side. Can be `null` (unrestricted, default) or `curb`.
|
||||
*
|
||||
* @returns {Object} containing `waypoints` and `trips`.
|
||||
* **`waypoints`**: an array of [`Waypoint`](#waypoint) objects representing all waypoints in input order.
|
||||
|
||||
@@ -343,6 +343,7 @@ int RestrictionsCheckCommand(const char *executable, const std::vector<std::stri
|
||||
// For each conditional restriction if condition is active than print a line
|
||||
for (auto &value : conditional_restrictions)
|
||||
{
|
||||
|
||||
const auto &location = value.location;
|
||||
const auto &restriction = value.restriction;
|
||||
|
||||
|
||||
@@ -36,7 +36,19 @@ SegmentLookupTable readSegmentValues(const std::vector<std::string> &paths)
|
||||
CSVFilesParser<Segment, SpeedSource> parser(
|
||||
1, qi::ulong_long >> ',' >> qi::ulong_long, qi::uint_ >> -(',' >> qi::double_));
|
||||
|
||||
return parser(paths);
|
||||
// Check consistency of keys in the result lookup table
|
||||
auto result = parser(paths);
|
||||
const auto found_inconsistency =
|
||||
std::find_if(std::begin(result.lookup), std::end(result.lookup), [](const auto &entry) {
|
||||
return entry.first.from == entry.first.to;
|
||||
});
|
||||
if (found_inconsistency != std::end(result.lookup))
|
||||
{
|
||||
util::Log(logWARNING) << "Empty segment in CSV with node " +
|
||||
std::to_string(found_inconsistency->first.from);
|
||||
}
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
TurnLookupTable readTurnValues(const std::vector<std::string> &paths)
|
||||
|
||||
+30
-79
@@ -7,6 +7,7 @@
|
||||
#include "extractor/node_based_edge.hpp"
|
||||
#include "extractor/packed_osm_ids.hpp"
|
||||
#include "extractor/restriction.hpp"
|
||||
#include "extractor/serialization.hpp"
|
||||
|
||||
#include "storage/io.hpp"
|
||||
|
||||
@@ -220,6 +221,12 @@ updateSegmentData(const UpdaterConfig &config,
|
||||
{
|
||||
auto u = osm_node_ids[nodes_range[segment_offset]];
|
||||
auto v = osm_node_ids[nodes_range[segment_offset + 1]];
|
||||
|
||||
// Self-loops are artifical segments (e.g. traffic light nodes), do not
|
||||
// waste time updating them with traffic data
|
||||
if (u == v)
|
||||
continue;
|
||||
|
||||
if (auto value = segment_speed_lookup({u, v}))
|
||||
{
|
||||
auto segment_length = segment_lengths[segment_offset];
|
||||
@@ -253,6 +260,12 @@ updateSegmentData(const UpdaterConfig &config,
|
||||
{
|
||||
auto u = osm_node_ids[nodes_range[segment_offset]];
|
||||
auto v = osm_node_ids[nodes_range[segment_offset + 1]];
|
||||
|
||||
// Self-loops are artifical segments (e.g. traffic light nodes), do not
|
||||
// waste time updating them with traffic data
|
||||
if (u == v)
|
||||
continue;
|
||||
|
||||
if (auto value = segment_speed_lookup({v, u}))
|
||||
{
|
||||
auto segment_length = segment_lengths[segment_offset];
|
||||
@@ -443,20 +456,16 @@ updateTurnPenalties(const UpdaterConfig &config,
|
||||
return updated_turns;
|
||||
}
|
||||
|
||||
bool IsRestrictionValid(const Timezoner &tz_handler,
|
||||
const extractor::ConditionalTurnRestriction &turn,
|
||||
const std::vector<util::Coordinate> &coordinates)
|
||||
bool IsRestrictionValid(const Timezoner &tz_handler, const extractor::ConditionalTurnPenalty &turn)
|
||||
{
|
||||
BOOST_ASSERT(!turn.condition.empty());
|
||||
BOOST_ASSERT(!turn.conditions.empty());
|
||||
|
||||
// we utilize the via node (first on ways) to represent the turn restriction
|
||||
auto const via = turn.Type() == extractor::RestrictionType::WAY_RESTRICTION
|
||||
? turn.AsWayRestriction().in_restriction.to
|
||||
: turn.AsNodeRestriction().via;
|
||||
auto const via = turn.location;
|
||||
|
||||
const auto lon = static_cast<double>(toFloating(coordinates[via].lon));
|
||||
const auto lat = static_cast<double>(toFloating(coordinates[via].lat));
|
||||
const auto &condition = turn.condition;
|
||||
const auto lon = static_cast<double>(toFloating(via.lon));
|
||||
const auto lat = static_cast<double>(toFloating(via.lat));
|
||||
const auto &conditions = turn.conditions;
|
||||
|
||||
// Get local time of the restriction
|
||||
const auto &local_time = tz_handler(point_t{lon, lat});
|
||||
@@ -469,85 +478,27 @@ bool IsRestrictionValid(const Timezoner &tz_handler,
|
||||
// TODO: parsing will fail for combined conditions, e.g. Sa-Su AND weight>7
|
||||
// http://wiki.openstreetmap.org/wiki/Conditional_restrictions#Combined_conditions:_AND
|
||||
|
||||
if (osrm::util::CheckOpeningHours(condition, *local_time))
|
||||
return true;
|
||||
|
||||
return false;
|
||||
return osrm::util::CheckOpeningHours(conditions, *local_time);
|
||||
}
|
||||
|
||||
std::vector<std::uint64_t>
|
||||
updateConditionalTurns(const UpdaterConfig &config,
|
||||
std::vector<TurnPenalty> &turn_weight_penalties,
|
||||
const std::vector<extractor::ConditionalTurnRestriction> &conditional_turns,
|
||||
std::vector<util::Coordinate> &coordinates,
|
||||
updateConditionalTurns(std::vector<TurnPenalty> &turn_weight_penalties,
|
||||
const std::vector<extractor::ConditionalTurnPenalty> &conditional_turns,
|
||||
Timezoner time_zone_handler)
|
||||
{
|
||||
// Mapped file pointer for turn indices
|
||||
boost::iostreams::mapped_file_source turn_index_region;
|
||||
auto turn_index_blocks = util::mmapFile<extractor::lookup::TurnIndexBlock>(
|
||||
config.GetPath(".osrm.turn_penalties_index"), turn_index_region);
|
||||
|
||||
std::vector<std::uint64_t> updated_turns;
|
||||
if (conditional_turns.size() == 0)
|
||||
return updated_turns;
|
||||
|
||||
// TODO make this into a function
|
||||
LookupTable<std::tuple<NodeID, NodeID>, NodeID> is_only_lookup;
|
||||
std::unordered_set<std::tuple<NodeID, NodeID, NodeID>,
|
||||
std::hash<std::tuple<NodeID, NodeID, NodeID>>>
|
||||
is_no_set;
|
||||
for (const auto &node_or_way : conditional_turns)
|
||||
for (const auto &penalty : conditional_turns)
|
||||
{
|
||||
// TODO handle conditional turn restrictions for via-ways (look-up doesn't work here)
|
||||
// https://github.com/Project-OSRM/osrm-backend/issues/2681#issuecomment-313376385
|
||||
if (node_or_way.Type() == extractor::RestrictionType::WAY_RESTRICTION)
|
||||
continue;
|
||||
|
||||
if (!IsRestrictionValid(time_zone_handler, node_or_way, coordinates))
|
||||
continue;
|
||||
|
||||
// TODO get rid of this, when we can handle way restrictions
|
||||
const auto &c = node_or_way.AsNodeRestriction();
|
||||
|
||||
// only add restrictions to the lookups if the restriction is valid now
|
||||
|
||||
if (node_or_way.is_only)
|
||||
if (IsRestrictionValid(time_zone_handler, penalty))
|
||||
{
|
||||
is_only_lookup.lookup.push_back({std::make_tuple(c.from, c.via), c.to});
|
||||
}
|
||||
else
|
||||
{
|
||||
is_no_set.insert({std::make_tuple(c.from, c.via, c.to)});
|
||||
std::cout << "Disabling: " << penalty.turn_offset << std::endl;
|
||||
turn_weight_penalties[penalty.turn_offset] = INVALID_TURN_PENALTY;
|
||||
updated_turns.push_back(penalty.turn_offset);
|
||||
}
|
||||
}
|
||||
|
||||
for (std::uint64_t edge_index = 0; edge_index < turn_weight_penalties.size(); ++edge_index)
|
||||
{
|
||||
const extractor::lookup::TurnIndexBlock internal_turn = turn_index_blocks[edge_index];
|
||||
|
||||
const auto is_no_tuple =
|
||||
std::make_tuple(internal_turn.from_id, internal_turn.via_id, internal_turn.to_id);
|
||||
const auto is_only_tuple = std::make_tuple(internal_turn.from_id, internal_turn.via_id);
|
||||
// turn has a no_* restriction
|
||||
if (is_no_set.find(is_no_tuple) != is_no_set.end())
|
||||
{
|
||||
util::Log(logDEBUG) << "Conditional penalty set on edge: " << edge_index;
|
||||
turn_weight_penalties[edge_index] = INVALID_TURN_PENALTY;
|
||||
updated_turns.push_back(edge_index);
|
||||
}
|
||||
// turn has an only_* restriction
|
||||
else if (is_only_lookup(is_only_tuple))
|
||||
{
|
||||
// with only_* restrictions, the turn on which the restriction is tagged is valid
|
||||
if (*is_only_lookup(is_only_tuple) == internal_turn.to_id)
|
||||
continue;
|
||||
|
||||
util::Log(logDEBUG) << "Conditional penalty set on edge: " << edge_index;
|
||||
turn_weight_penalties[edge_index] = INVALID_TURN_PENALTY;
|
||||
updated_turns.push_back(edge_index);
|
||||
}
|
||||
}
|
||||
|
||||
return updated_turns;
|
||||
}
|
||||
}
|
||||
@@ -638,7 +589,7 @@ Updater::LoadAndUpdateEdgeExpandedGraph(std::vector<extractor::EdgeBasedEdge> &e
|
||||
load_profile_properties);
|
||||
}
|
||||
|
||||
std::vector<extractor::ConditionalTurnRestriction> conditional_turns;
|
||||
std::vector<extractor::ConditionalTurnPenalty> conditional_turns;
|
||||
if (update_conditional_turns)
|
||||
{
|
||||
using storage::io::FileReader;
|
||||
@@ -696,8 +647,8 @@ Updater::LoadAndUpdateEdgeExpandedGraph(std::vector<extractor::EdgeBasedEdge> &e
|
||||
}
|
||||
const Timezoner time_zone_handler = Timezoner(config.tz_file_path, config.valid_now);
|
||||
|
||||
auto updated_turn_penalties = updateConditionalTurns(
|
||||
config, turn_weight_penalties, conditional_turns, coordinates, time_zone_handler);
|
||||
auto updated_turn_penalties =
|
||||
updateConditionalTurns(turn_weight_penalties, conditional_turns, time_zone_handler);
|
||||
const auto offset = updated_segments.size();
|
||||
updated_segments.resize(offset + updated_turn_penalties.size());
|
||||
// we need to re-compute all edges that have updated turn penalties.
|
||||
|
||||
@@ -11,7 +11,7 @@ namespace util
|
||||
|
||||
//----------------------------------------------------------------
|
||||
NodeIdVectorToLineString::NodeIdVectorToLineString(
|
||||
const std::vector<extractor::QueryNode> &node_coordinates)
|
||||
const std::vector<util::Coordinate> &node_coordinates)
|
||||
: node_coordinates(node_coordinates)
|
||||
{
|
||||
}
|
||||
@@ -32,7 +32,7 @@ operator()(const std::vector<NodeID> &node_ids,
|
||||
|
||||
//----------------------------------------------------------------
|
||||
NodeIdVectorToMultiPoint::NodeIdVectorToMultiPoint(
|
||||
const std::vector<extractor::QueryNode> &node_coordinates)
|
||||
const std::vector<util::Coordinate> &node_coordinates)
|
||||
: node_coordinates(node_coordinates)
|
||||
{
|
||||
}
|
||||
|
||||
File diff suppressed because one or more lines are too long
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user