Compare commits

...

23 Commits

Author SHA1 Message Date
Moritz Kobitzsch 1da044f3e3 fix roundabout-handling when name changes 2016-06-17 11:19:27 -07:00
Patrick Niklaus 45516ef534 Enable travis builds for 5.2 branch 2016-06-14 14:36:41 +02:00
Patrick Niklaus 532fda267f [skip ci] Update changelog for 5.2.1
Conflicts:
	CHANGELOG.md
2016-06-14 14:32:33 +02:00
Daniel Patterson 494845b160 Copy data to beginning of buffer, not end. (#2542)
Copy data to beginning of buffer, not end.
2016-06-13 12:59:42 -07:00
Patrick Niklaus 0fc823041e Removed debug code 2016-06-13 17:57:33 +02:00
Patrick Niklaus 71eae4137d [skip ci] Update changelog 2016-06-13 17:27:53 +02:00
Moritz Kobitzsch 47b19f209b prefer obvious turn assignment over forks 2016-06-13 15:00:18 +02:00
Moritz Kobitzsch 2b5355edca improve slipway handling to allow multiple styles of turn lanes / turn roads 2016-06-13 11:56:50 +02:00
Patrick Niklaus e9a0beb4e8 Fix shared memory encoding for node-ids 2016-06-12 20:50:57 +02:00
Vladimir Kurchatkin 6bdfe68897 Add feature name to vector tiles (#2488) 2016-06-10 11:15:14 -07:00
Daniel J. Hofmann cf2d2b6763 Boost.Test Testing Docs 2016-06-10 19:03:44 +02:00
Moritz Kobitzsch 95cd44f34f add directions guide 2016-06-10 19:03:44 +02:00
Moritz Kobitzsch d330e60d40 added a guide on writing good cucumber tests for osrm 2016-06-10 19:03:44 +02:00
Moritz Kobitzsch 99004bbec8 add testcase 2016-06-10 10:20:39 +02:00
Emil Tin bbcc728a07 Update http.md
clarify "new name" instruction
2016-06-10 09:42:13 +02:00
Daniel J. Hofmann 033dc0a72d Pre-allocate up-front whenever possible 2016-06-09 16:06:27 +02:00
Patrick Niklaus 1c140a112a Make sure we also reserve space for destination and pronunciation 2016-06-08 10:58:11 +02:00
Moritz Kobitzsch 312e86eb58 handle merge on collapsed instructions 2016-06-06 11:55:14 +02:00
Moritz Kobitzsch 1dfdb38d4a improve collapse-handling 2016-06-06 10:05:18 +02:00
Dane Springmeyer dfafe7dc5f Install clang-3.8 via mason binary 2016-06-04 12:15:29 +02:00
Dane Springmeyer 6ecc123d15 Fix various issues with pkg-config 2016-06-04 12:08:54 +02:00
Daniel J. Hofmann 6f322d2140 Silence multiline comment warning 2016-06-03 14:47:45 +02:00
Daniel J. Hofmann dfa762bccc Pronunciation.
Spelling is hard. Maybe this time. /cc @themarex @systemed
2016-06-02 16:35:21 +02:00
46 changed files with 1339 additions and 368 deletions
+16 -11
View File
@@ -13,6 +13,7 @@ notifications:
branches: branches:
only: only:
- master - master
- "5.2"
cache: cache:
ccache: true ccache: true
@@ -49,16 +50,13 @@ matrix:
packages: ['g++-4.8', 'libbz2-dev', 'libstxxl-dev', 'libstxxl1', 'libxml2-dev', 'libzip-dev', 'lua5.1', 'liblua5.1-0-dev', 'libtbb-dev', 'libgdal-dev', 'libluabind-dev', 'libboost-all-dev', 'ccache'] packages: ['g++-4.8', 'libbz2-dev', 'libstxxl-dev', 'libstxxl1', 'libxml2-dev', 'libzip-dev', 'lua5.1', 'liblua5.1-0-dev', 'libtbb-dev', 'libgdal-dev', 'libluabind-dev', 'libboost-all-dev', 'ccache']
env: CCOMPILER='gcc-4.8' CXXCOMPILER='g++-4.8' BUILD_TYPE='Debug' env: CCOMPILER='gcc-4.8' CXXCOMPILER='g++-4.8' BUILD_TYPE='Debug'
# LLVM APT servers switched off, commenting Clang builds out as they will always fail now - os: linux
# http://lists.llvm.org/pipermail/llvm-foundation/2016-June/000025.html compiler: "clang-3.8-debug"
# addons: &clang38
# - os: linux apt:
# compiler: "clang-3.8-debug" sources: ['ubuntu-toolchain-r-test']
# addons: &clang38 packages: ['libstdc++-5-dev', 'libbz2-dev', 'libstxxl-dev', 'libstxxl1', 'libxml2-dev', 'libzip-dev', 'lua5.1', 'liblua5.1-0-dev', 'libtbb-dev', 'libgdal-dev', 'libluabind-dev', 'libboost-all-dev', 'ccache']
# apt: env: CLANG_VERSION='3.8.0' BUILD_TYPE='Debug' RUN_CLANG_FORMAT=ON
# sources: ['llvm-toolchain-precise-3.8', 'ubuntu-toolchain-r-test']
# packages: ['clang-3.8', 'libbz2-dev', 'libstxxl-dev', 'libstxxl1', 'libxml2-dev', 'libzip-dev', 'lua5.1', 'liblua5.1-0-dev', 'libtbb-dev', 'libgdal-dev', 'libluabind-dev', 'libboost-all-dev', 'ccache']
# env: CCOMPILER='clang-3.8' CXXCOMPILER='clang++-3.8' BUILD_TYPE='Debug' RUN_CLANG_FORMAT=ON
- os: osx - os: osx
osx_image: xcode7.3 osx_image: xcode7.3
@@ -124,6 +122,13 @@ before_install:
- export PATH=${DEPS_DIR}/bin:${PATH} && mkdir -p ${DEPS_DIR} - export PATH=${DEPS_DIR}/bin:${PATH} && mkdir -p ${DEPS_DIR}
- CMAKE_URL="https://mason-binaries.s3.amazonaws.com/${TRAVIS_OS_NAME}-x86_64/cmake/3.5.2.tar.gz" - CMAKE_URL="https://mason-binaries.s3.amazonaws.com/${TRAVIS_OS_NAME}-x86_64/cmake/3.5.2.tar.gz"
- travis_retry wget --quiet -O - ${CMAKE_URL} | tar --strip-components=1 -xz -C ${DEPS_DIR} - travis_retry wget --quiet -O - ${CMAKE_URL} | tar --strip-components=1 -xz -C ${DEPS_DIR}
- |
if [[ ${CLANG_VERSION:-false} != false ]]; then
export CCOMPILER='clang'
export CXXCOMPILER='clang++'
CLANG_URL="https://mason-binaries.s3.amazonaws.com/${TRAVIS_OS_NAME}-x86_64/clang/${CLANG_VERSION}.tar.gz"
travis_retry wget --quiet -O - ${CLANG_URL} | tar --strip-components=1 -xz -C ${DEPS_DIR}
fi
- | - |
if [[ "${TRAVIS_OS_NAME}" == "osx" ]]; then if [[ "${TRAVIS_OS_NAME}" == "osx" ]]; then
# implicit deps, but seem to be installed by default with recent images: libxml2 GDAL boost # implicit deps, but seem to be installed by default with recent images: libxml2 GDAL boost
@@ -152,7 +157,7 @@ install:
fi fi
- popd - popd
- mkdir example/build && pushd example/build - mkdir example/build && pushd example/build
- cmake .. - cmake .. -DCMAKE_BUILD_TYPE=${BUILD_TYPE}
- make - make
- popd - popd
+60 -2
View File
@@ -1,20 +1,78 @@
# 5.2.3
- Bugfixes:
- Fixed an issue with name changes in roundabouts that could result in crashes
# 5.2.2
Changes from 5.2.1
- Bugfixes:
- Buffer overrun in tile plugin response handling
# 5.2.1
Changes from 5.2.0
- Bugfixes:
- Removed debug statement that was spamming the console
# 5.2.0
Changes from 5.2.0 RC2
- Bugfixes:
- Fixed crash when loading shared memory caused by invalid OSM IDs segment size.
- Various small instructions handling fixes
Changes from 5.1.0
- API:
- new parameter `annotations` for `route`, `trip` and `match` requests. Returns additional data about each
coordinate along the selected/matched route line per `RouteLeg`:
- duration of each segment
- distance of each segment
- OSM node ids of all segment endpoints
- Introducing Intersections for Route Steps. This changes the API format in multiple ways.
- `bearing_before`/`bearing_after` of `StepManeuver` are now deprecated and will be removed in the next major release
- `location` of `StepManeuvers` is now deprecated and will be removed in the next major release
- every `RouteStep` now has property `intersections` containing a list of `Intersection` objects.
- Support for destination signs. New member `destinations` in `RouteStep`, based on `destination` and `destination:ref`
- Support for name pronunciations. New member `pronunciation` in `RouteStep`, based on `name:pronunciation`
- Profile changes:
- duration parser now accepts P[n]DT[n]H[n]M[n]S, P[n]W, PTHHMMSS and PTHH:MM:SS ISO8601 formats.
- `result.destinations` allows you to set a way's destinations
- `result.pronunciation` allows you to set way name pronunciations
- `highway=motorway_link` no longer implies `oneway` as per the OSM Wiki
- Infrastructure:
- BREAKING: Changed the on-disk encoding of the StaticRTree to reduce ramIndex file size. This breaks the **data format**
- BREAKING: Intersection Classification adds a new file to the mix (osrm.icd). This breaks the fileformat for older versions.
- Better support for osrm-routed binary upgrade on the fly [UNIX specific]:
- Open sockets with SO_REUSEPORT to allow multiple osrm-routed processes serving requests from the same port.
- Add SIGNAL_PARENT_WHEN_READY environment variable to enable osrm-routed signal its parent with USR1 when it's running and waiting for requests.
- Disable http access logging via DISABLE_ACCESS_LOGGING environment variable.
- Guidance:
- BREAKING: modifies the file format with new internal identifiers
- improved detection of turning streets, not reporting new-name in wrong situations
- improved handling of sliproads (emit turns instead of 'take the ramp')
- improved collapsing of instructions. Some 'new name' instructions will be suppressed if they are without alternative and the segment is short
- Bugfixes
- fixed broken summaries for very short routes
# 5.2.0 RC2 # 5.2.0 RC2
Changes from 5.2.0 RC1 Changes from 5.2.0 RC1
- Guidance: - Guidance:
- improved handling of sliproads (emit turns instead of 'take the ramp') - improved handling of sliproads (emit turns instead of 'take the ramp')
- improved collapsing of instructions. Some 'new name' instructions will be suppressed if they are without alternative and the segment is short
- BREAKING: modifies the file format with new internal identifiers - BREAKING: modifies the file format with new internal identifiers
- API: - API:
- paramater `annotate` was renamed to `annotations`. - paramater `annotate` was renamed to `annotations`.
- `annotation` as accidentally placed in `Route` instead of `RouteLeg` - `annotation` as accidentally placed in `Route` instead of `RouteLeg`
- Support for destination signs. New member `destinations` in `RouteStep`, based on `destination` and `destination:ref` - Support for destination signs. New member `destinations` in `RouteStep`, based on `destination` and `destination:ref`
- Support for name pronounciations. New member `pronounciation` in `RouteStep`, based on `name:pronounciation` - Support for name pronunciations. New member `pronunciation` in `RouteStep`, based on `name:pronunciation`
- Add `nodes` property to `annotation` in `RouteLeg` containing the ids of nodes covered by the route - Add `nodes` property to `annotation` in `RouteLeg` containing the ids of nodes covered by the route
- Profile changes: - Profile changes:
- `result.destinations` allows you to set a way's destinations - `result.destinations` allows you to set a way's destinations
- `result.pronounciation` allows you to set way name pronounciations - `result.pronunciation` allows you to set way name pronunciations
- `highway=motorway_link` no longer implies `oneway` as per the OSM Wiki - `highway=motorway_link` no longer implies `oneway` as per the OSM Wiki
- Infrastructure - Infrastructure
+67 -27
View File
@@ -12,6 +12,22 @@ set(OSRM_VERSION_MAJOR 5)
set(OSRM_VERSION_MINOR 2) set(OSRM_VERSION_MINOR 2)
set(OSRM_VERSION_PATCH 0) set(OSRM_VERSION_PATCH 0)
# these two functions build up custom variables:
# OSRM_INCLUDE_PATHS and OSRM_DEFINES
# These variables we want to pass to
# include_directories and add_definitions for both
# this build and for sharing externally via pkg-config
function(add_dependency_includes includes)
list(APPEND OSRM_INCLUDE_PATHS "${includes}")
set(OSRM_INCLUDE_PATHS "${OSRM_INCLUDE_PATHS}" PARENT_SCOPE)
endfunction(add_dependency_includes)
function(add_dependency_defines defines)
list(APPEND OSRM_DEFINES "${defines}")
set(OSRM_DEFINES "${OSRM_DEFINES}" PARENT_SCOPE)
endfunction(add_dependency_defines)
set(CMAKE_EXPORT_COMPILE_COMMANDS ON) set(CMAKE_EXPORT_COMPILE_COMMANDS ON)
include(CheckCXXCompilerFlag) include(CheckCXXCompilerFlag)
include(FindPackageHandleStandardArgs) include(FindPackageHandleStandardArgs)
@@ -164,7 +180,7 @@ elseif(${CMAKE_CXX_COMPILER_ID} STREQUAL "GNU")
# using GCC # using GCC
set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -Wall -Wextra -pedantic -Wuninitialized -Wunreachable-code -Wstrict-overflow=1 -D_FORTIFY_SOURCE=2 ${COLOR_FLAG} -fPIC") set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -Wall -Wextra -pedantic -Wuninitialized -Wunreachable-code -Wstrict-overflow=1 -D_FORTIFY_SOURCE=2 ${COLOR_FLAG} -fPIC")
if(WIN32) # using mingw if(WIN32) # using mingw
add_definitions(-DWIN32) add_dependency_defines(-DWIN32)
set(OPTIONAL_SOCKET_LIBS ws2_32 wsock32) set(OPTIONAL_SOCKET_LIBS ws2_32 wsock32)
endif() endif()
elseif(${CMAKE_CXX_COMPILER_ID} STREQUAL "Intel") elseif(${CMAKE_CXX_COMPILER_ID} STREQUAL "Intel")
@@ -173,12 +189,12 @@ elseif(${CMAKE_CXX_COMPILER_ID} STREQUAL "Intel")
elseif(${CMAKE_CXX_COMPILER_ID} STREQUAL "MSVC") elseif(${CMAKE_CXX_COMPILER_ID} STREQUAL "MSVC")
# using Visual Studio C++ # using Visual Studio C++
set(BOOST_COMPONENTS ${BOOST_COMPONENTS} date_time chrono zlib) set(BOOST_COMPONENTS ${BOOST_COMPONENTS} date_time chrono zlib)
add_definitions(-DBOOST_LIB_DIAGNOSTIC) add_dependency_defines(-DBOOST_LIB_DIAGNOSTIC)
add_definitions(-D_CRT_SECURE_NO_WARNINGS) add_dependency_defines(-D_CRT_SECURE_NO_WARNINGS)
add_definitions(-DNOMINMAX) # avoid min and max macros that can break compilation add_dependency_defines(-DNOMINMAX) # avoid min and max macros that can break compilation
add_definitions(-D_USE_MATH_DEFINES) #needed for M_PI with cmath.h add_dependency_defines(-D_USE_MATH_DEFINES) #needed for M_PI with cmath.h
add_definitions(-D_WIN32_WINNT=0x0501) add_dependency_defines(-D_WIN32_WINNT=0x0501)
add_definitions(-DXML_STATIC) add_dependency_defines(-DXML_STATIC)
find_library(ws2_32_LIBRARY_PATH ws2_32) find_library(ws2_32_LIBRARY_PATH ws2_32)
target_link_libraries(osrm-extract wsock32 ws2_32) target_link_libraries(osrm-extract wsock32 ws2_32)
endif() endif()
@@ -205,7 +221,7 @@ set(CMAKE_MODULE_LINKER_FLAGS "${CMAKE_MODULE_LINKER_FLAGS} ${LINKER_FLAGS}")
# Activate C++11 # Activate C++11
if(NOT ${CMAKE_CXX_COMPILER_ID} STREQUAL "MSVC") if(NOT ${CMAKE_CXX_COMPILER_ID} STREQUAL "MSVC")
set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -std=c++11 ") set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -std=c++11")
endif() endif()
# Configuring other platform dependencies # Configuring other platform dependencies
@@ -230,41 +246,54 @@ endif()
list(APPEND CMAKE_MODULE_PATH "${CMAKE_CURRENT_SOURCE_DIR}/third_party/libosmium/cmake") list(APPEND CMAKE_MODULE_PATH "${CMAKE_CURRENT_SOURCE_DIR}/third_party/libosmium/cmake")
set(OSMIUM_INCLUDE_DIR "${CMAKE_CURRENT_SOURCE_DIR}/third_party/libosmium/include") set(OSMIUM_INCLUDE_DIR "${CMAKE_CURRENT_SOURCE_DIR}/third_party/libosmium/include")
find_package(Osmium REQUIRED COMPONENTS io) find_package(Osmium REQUIRED COMPONENTS io)
include_directories(SYSTEM ${OSMIUM_INCLUDE_DIRS}) add_dependency_includes(${OSMIUM_INCLUDE_DIR})
find_package(Boost 1.49.0 REQUIRED COMPONENTS ${BOOST_COMPONENTS}) find_package(Boost 1.49.0 REQUIRED COMPONENTS ${BOOST_COMPONENTS})
# collect a subset of the boost libraries needed
# by libosrm
foreach(lib ${Boost_LIBRARIES})
if(NOT WIN32)
if(lib MATCHES filesystem OR lib MATCHES thread OR lib MATCHES iostreams OR lib MATCHES system)
list(APPEND BOOST_ENGINE_LIBRARIES "${lib}")
endif()
else()
list(APPEND BOOST_ENGINE_LIBRARIES "${lib}")
endif()
endforeach(lib)
if(NOT WIN32 AND NOT Boost_USE_STATIC_LIBS) if(NOT WIN32 AND NOT Boost_USE_STATIC_LIBS)
add_definitions(-DBOOST_TEST_DYN_LINK) add_dependency_defines(-DBOOST_TEST_DYN_LINK)
endif() endif()
add_definitions(-DBOOST_SPIRIT_USE_PHOENIX_V3) add_dependency_defines(-DBOOST_SPIRIT_USE_PHOENIX_V3)
add_definitions(-DBOOST_RESULT_OF_USE_DECLTYPE) add_dependency_defines(-DBOOST_RESULT_OF_USE_DECLTYPE)
add_definitions(-DBOOST_FILESYSTEM_NO_DEPRECATED) add_dependency_defines(-DBOOST_FILESYSTEM_NO_DEPRECATED)
include_directories(SYSTEM ${Boost_INCLUDE_DIRS}) add_dependency_includes(${Boost_INCLUDE_DIRS})
find_package(Threads REQUIRED) find_package(Threads REQUIRED)
find_package(TBB REQUIRED) find_package(TBB REQUIRED)
include_directories(SYSTEM ${TBB_INCLUDE_DIR}) add_dependency_includes(${TBB_INCLUDE_DIR})
if(WIN32 AND CMAKE_BUILD_TYPE MATCHES Debug) if(WIN32 AND CMAKE_BUILD_TYPE MATCHES Debug)
set(TBB_LIBRARIES ${TBB_DEBUG_LIBRARIES}) set(TBB_LIBRARIES ${TBB_DEBUG_LIBRARIES})
endif() endif()
find_package(Luabind REQUIRED) find_package(Luabind REQUIRED)
include(check_luabind) include(check_luabind)
include_directories(SYSTEM ${LUABIND_INCLUDE_DIR}) add_dependency_includes(${LUABIND_INCLUDE_DIR})
set(USED_LUA_LIBRARIES ${LUA_LIBRARY}) set(USED_LUA_LIBRARIES ${LUA_LIBRARY})
if(LUAJIT_FOUND) if(LUAJIT_FOUND)
set(USED_LUA_LIBRARIES, LUAJIT_LIBRARIES) set(USED_LUA_LIBRARIES, LUAJIT_LIBRARIES)
endif() endif()
include_directories(SYSTEM ${LUA_INCLUDE_DIR}) add_dependency_includes(${LUA_INCLUDE_DIR})
find_package(EXPAT REQUIRED) find_package(EXPAT REQUIRED)
include_directories(SYSTEM ${EXPAT_INCLUDE_DIRS}) add_dependency_includes(${EXPAT_INCLUDE_DIRS})
find_package(STXXL REQUIRED) find_package(STXXL REQUIRED)
include_directories(SYSTEM ${STXXL_INCLUDE_DIR}) add_dependency_includes(${STXXL_INCLUDE_DIR})
set(OpenMP_FIND_QUIETLY ON) set(OpenMP_FIND_QUIETLY ON)
find_package(OpenMP) find_package(OpenMP)
@@ -274,16 +303,19 @@ if(OPENMP_FOUND)
endif() endif()
find_package(BZip2 REQUIRED) find_package(BZip2 REQUIRED)
include_directories(SYSTEM ${BZIP_INCLUDE_DIRS}) add_dependency_includes(${BZIP2_INCLUDE_DIR})
find_package(ZLIB REQUIRED) find_package(ZLIB REQUIRED)
include_directories(SYSTEM ${ZLIB_INCLUDE_DIRS}) add_dependency_includes(${ZLIB_INCLUDE_DIRS})
if (ENABLE_JSON_LOGGING) if (ENABLE_JSON_LOGGING)
message(STATUS "Enabling json logging") message(STATUS "Enabling json logging")
add_definitions(-DENABLE_JSON_LOGGING) add_dependency_defines(-DENABLE_JSON_LOGGING)
endif() endif()
add_definitions(${OSRM_DEFINES})
include_directories(SYSTEM ${OSRM_INCLUDE_PATHS})
# Binaries # Binaries
target_link_libraries(osrm-datastore osrm_store ${Boost_LIBRARIES}) target_link_libraries(osrm-datastore osrm_store ${Boost_LIBRARIES})
target_link_libraries(osrm-extract osrm_extract ${Boost_LIBRARIES}) target_link_libraries(osrm-extract osrm_extract ${Boost_LIBRARIES})
@@ -312,9 +344,8 @@ set(CONTRACTOR_LIBRARIES
${MAYBE_RT_LIBRARY} ${MAYBE_RT_LIBRARY}
${MAYBE_COVERAGE_LIBRARIES}) ${MAYBE_COVERAGE_LIBRARIES})
set(ENGINE_LIBRARIES set(ENGINE_LIBRARIES
${Boost_LIBRARIES} ${BOOST_ENGINE_LIBRARIES}
${CMAKE_THREAD_LIBS_INIT} ${CMAKE_THREAD_LIBS_INIT}
${STXXL_LIBRARY}
${TBB_LIBRARIES} ${TBB_LIBRARIES}
${MAYBE_RT_LIBRARY} ${MAYBE_RT_LIBRARY}
${MAYBE_COVERAGE_LIBRARIES} ${MAYBE_COVERAGE_LIBRARIES}
@@ -414,14 +445,23 @@ foreach(lib ${ENGINE_LIBRARIES})
set(ENGINE_LIBRARY_LISTING "${ENGINE_LIBRARY_LISTING} -L${ENGINE_LIBRARY_PATH} -l${ENGINE_LIBRARY_NAME}") set(ENGINE_LIBRARY_LISTING "${ENGINE_LIBRARY_LISTING} -L${ENGINE_LIBRARY_PATH} -l${ENGINE_LIBRARY_NAME}")
endforeach() endforeach()
configure_file(${CMAKE_CURRENT_SOURCE_DIR}/cmake/pkgconfig.in libosrm.pc @ONLY)
install(FILES ${PROJECT_BINARY_DIR}/libosrm.pc DESTINATION lib/pkgconfig)
if(BUILD_DEBIAN_PACKAGE) if(BUILD_DEBIAN_PACKAGE)
include(CPackDebianConfig) include(CPackDebianConfig)
include(CPack) include(CPack)
endif() endif()
function(JOIN VALUES GLUE OUTPUT)
string (REPLACE ";" "${GLUE}" _TMP_STR "${VALUES}")
set (${OUTPUT} "${_TMP_STR}" PARENT_SCOPE)
endfunction()
# Set up variables, then write to pkgconfig file
JOIN("${OSRM_DEFINES}" " " OSRM_DEFINES_STRING)
JOIN("-I${OSRM_INCLUDE_PATHS}" " -I" OSRM_INCLUDE_PATHS_STRING)
configure_file(${CMAKE_CURRENT_SOURCE_DIR}/cmake/pkgconfig.in libosrm.pc @ONLY)
install(FILES ${PROJECT_BINARY_DIR}/libosrm.pc DESTINATION lib/pkgconfig)
# add a target to generate API documentation with Doxygen # add a target to generate API documentation with Doxygen
find_package(Doxygen) find_package(Doxygen)
if(DOXYGEN_FOUND) if(DOXYGEN_FOUND)
+1 -1
View File
@@ -8,4 +8,4 @@ Version: v@OSRM_VERSION_MAJOR@.@OSRM_VERSION_MINOR@.@OSRM_VERSION_PATCH@
Requires: Requires:
Libs: -L${libdir} -losrm Libs: -L${libdir} -losrm
Libs.private: @ENGINE_LIBRARY_LISTING@ Libs.private: @ENGINE_LIBRARY_LISTING@
Cflags: -I${includedir} -I${includedir}/osrm Cflags: -I${includedir} -I${includedir}/osrm @OSRM_INCLUDE_PATHS_STRING@ @OSRM_DEFINES_STRING@ @CMAKE_CXX_FLAGS@
+1 -1
View File
@@ -485,7 +485,7 @@ step.
| `type` | Description | | `type` | Description |
|-------------------|--------------------------------------------------------------| |-------------------|--------------------------------------------------------------|
| turn | a basic turn into direction of the `modifier` | | turn | a basic turn into direction of the `modifier` |
| new name | no turn is taken, but the road name changes. The Road can take a turn itself, following `modifier` | | new name | no turn is taken/possible, but the road name changes. The road can take a turn itself, following `modifier`. |
| depart | indicates the departure of the leg | | depart | indicates the departure of the leg |
| arrive | indicates the destination of the leg | | arrive | indicates the destination of the leg |
| merge | merge onto a street (e.g. getting on the highway from a ramp, the `modifier specifies the direction of the merge`) | | merge | merge onto a street (e.g. getting on the highway from a ramp, the `modifier specifies the direction of the merge`) |
+239
View File
@@ -0,0 +1,239 @@
# Testsuite
OSRM comes with a testsuite containing both unit-tests using the Boost library and cucucmber.js for scenario driven testing.
## Unit Tests
For a general introduction on Boost.Test have a look at [its docs](http://www.boost.org/doc/libs/1_60_0/libs/test/doc/html/index.html).
### Separate Test Binaries
Unit tests should be registered according to the sub-project they're in.
If you want to write tests for utility functions, add them to the utility test binary.
See `CMakeLists.txt` in the unit test directory for how to register new unit tests.
### Using Boost.Test Primitives
There is a difference between only reporting a failed condition and aborting the test right at a failed condition.
Have a look at [`BOOST_CHECK` vs `BOOST_REQUIRE`](http://www.boost.org/doc/libs/1_60_0/libs/test/doc/html/boost_test/utf_reference/testing_tool_ref/assertion_boost_level.html).
Instead of manually checking e.g. for equality, less than, if a function throws etc. use their [corresponding Boost.Test primitives](http://www.boost.org/doc/libs/1_60_0/libs/test/doc/html/boost_test/utf_reference/testing_tool_ref.html).
If you use `BOOST_CHECK_EQUAL` you have to implement `operator<<` for your type so that Boost.Test can print mismatches.
If you do not want to do this, define `BOOST_TEST_DONT_PRINT_LOG_VALUE` (and undef it after the check call) or sidestep it with `BOOST_CHECK(fst == snd);`.
### Test Fixture
If you need to test features on a real dataset (think about this twice: prefer cucumber and dataset-independent tests for their reproducibility and minimality), there is a fixed dataset in `test/data`.
This dataset is a small extract and may not even contain all tags or edge cases.
Furthermore this dataset is not in sync with what you see in up-to-date OSM maps or on the demo server.
See the library tests for how to add new dataset dependent tests.
## Cucumber
For a general introduction on cucumber in our testsuite, have a look at [the wiki](https://github.com/Project-OSRM/osrm-backend/wiki/Cucumber-Test-Suite).
This documentation aims to supply a guideline on how to write cucumber tests that test new features introduced into osrm.
### Test the feature
It is often tempting to reduce the test to a path and accompanying instructions. Instructions can and will change over the course of improving guidance.
Instructions should only be used when writing a feature located in `features/guidance`. All other features should avoid using instructions at all.
### Write Tests to Scale
OSRM is a navigation engine. Tests should always consider this background.
An important implication is the grid size. If tests use a very small grid size, you run into the chance of instructions being omitted.
For example:
```
Background:
Given the profile "car"
Given a grid size of 10 meters
Scenario: Testbot - Straight Road
Given the node map
| a | b | c | d |
And the ways
| nodes | highway |
| ab | primary |
| bc | primary |
| cd | primary |
When I route I should get
| from | to | route |
| a | d | ab,bc,cd,cd |
```
In a navigation engine, the instructions
- depart east on ab
- in 10 meters the road name changes to bc
- in 10 meters the road name changes to cd
- you arrived at cd
would be impossible to announce and not helpful at all.
Since no actual choices exist, the route you get could result in `ab,cd` and simply say `depart` and `arrive`.
To prevent such surprises, always consider the availability of other roads and use grid sizes/road lengths that correspond to actually reasonable scenarios in a road network.
### Use names
If you specify many nodes in close succession to present a specific road geometry, consider using `name` to indicate to OSRM that the segment is a single road.
```
Background:
Given the profile "car"
Given a grid size of 10 meters
Scenario: Testbot - Straight Road
Given the node map
| a | b | c | d |
And the ways
| nodes | highway | name |
| ab | primary | road |
| bc | primary | road |
| cd | primary | road |
When I route I should get
| from | to | route | turns |
| a | d | road,road | depart,arrive |
```
Guidance guarantees only essential maneuvers. You will always see `depart` and `arrive` as well as all turns that are not obvious.
So the following scenario does not change the instructions
```
Background:
Given the profile "car"
Given a grid size of 10 meters
Scenario: Testbot - Straight Road
Given the node map
| a | b |
| d | c |
And the ways
| nodes | highway | name |
| ab | primary | road |
| bc | primary | road |
| cd | primary | road |
When I route I should get
| from | to | route | turns |
| a | d | road,road | depart,arrive |
```
but if we modify it to
```
Background:
Given the profile "car"
Given a grid size of 10 meters
Scenario: Testbot - Straight Road
Given the node map
| a | b | e |
| d | c | |
And the ways
| nodes | highway | name |
| ab | primary | road |
| bc | primary | road |
| cd | primary | road |
| be | primary | turn |
When I route I should get
| from | to | route | turns |
| a | d | road,road,road | depart,continue right,arrive |
```
### Test all directions
Modelling a road as roundabout has an implied oneway tag associated with it. In the following case, we can route from `a` to `d` but not from `d` to `a`.
To discover those errors, make sure to check for all allowed directions.
```
Scenario: Enter and Exit mini roundabout with sharp angle # features/guidance/mini-roundabout.feature:37
Given the profile "car" # features/step_definitions/data.js:8
Given a grid size of 10 meters # features/step_definitions/data.js:20
Given the node map # features/step_definitions/data.js:45
| a | b | |
| | c | d |
And the ways # features/step_definitions/data.js:128
| nodes | highway | name |
| ab | tertiary | MySt |
| bc | roundabout | |
| cd | tertiary | MySt |
When I route I should get # features/step_definitions/routing.js:4
| from | to | route | turns | # |
| a | d | MySt,MySt | depart,arrive | # suppress multiple enter/exit mini roundabouts |
| d | a | MySt,MySt | depart,arrive | # suppress multiple enter/exit mini roundabouts |
Tables were not identical:
| from | to | route | turns | #
| a | d | MySt,MySt | depart,arrive | # suppress multiple enter/exit mini roundabouts |
| (-) d | (-) a | (-) MySt,MySt | (-) depart,arrive | (-) # suppress multiple enter/exit mini roundabouts |
| (+) d | (+) a | (+) | (+) | (+) # suppress multiple enter/exit mini roundabouts |
```
### Prevent Randomness
Some features in OSRM can result in strange experiences during testcases. To prevent some of these issues, follow the guidelines below.
#### Use Waypoints
Using grid nodes as waypoints offers the chance of unwanted side effects.
OSRM converts the grid into a so called edge-based graph.
```
Scenario: Testbot - Intersection
Given the node map
| | e | |
| b | a | d |
| | c | |
And the ways
| nodes | highway | oneway |
| ab | primary | yes |
| ac | primary | yes |
| ad | primary | yes |
| ae | primary | yes |
```
Selecting `a` as a `waypoint` results in four possible starting locations. Which one of the routes `a,b`, `a,c`, `a,d`, or `a,e` is found is pure chance and depends on the order in the static `r-tree`.
To guarantee discovery, use:
```
Scenario: Testbot - Intersection
Given the node map
| | | e | | |
| | | 4 | | |
| b | 1 | a | 3 | d |
| | | 2 | | |
| | | c | | |
And the ways
| nodes | highway | oneway |
| ab | primary | yes |
| ac | primary | yes |
| ad | primary | yes |
| ae | primary | yes |
```
And use `1`,`2`,`3`, and `4` as starting waypoints. The routes `1,b`, `2,c`, `3,d`, and `4,e` can all be discovered.
#### Allow For Small Offsets
Whenever you are independent of the start location (see use waypoints), the waypoint chosen as start/end location can still influence distances/durations.
If you are testing for a duration metric, allow for a tiny offset to ensure a passing test in the presence of rounding/snapping issues.
#### Don't Rely on Alternatives
Alternative route discovery is a random feature in itself. The discovery of routes depends on the contraction order of roads and cannot be assumed successful, ever.
+8 -5
View File
@@ -6,10 +6,13 @@ Please create a directory and run cmake from there, passing the path to this sou
This process created the file `CMakeCache.txt' and the directory `CMakeFiles'. Please delete them.") This process created the file `CMakeCache.txt' and the directory `CMakeFiles'. Please delete them.")
endif() endif()
if(NOT CMAKE_BUILD_TYPE MATCHES Debug)
set(CMAKE_BUILD_TYPE Release)
endif()
project(osrm-example C CXX) project(osrm-example C CXX)
list(APPEND CMAKE_MODULE_PATH "${CMAKE_CURRENT_SOURCE_DIR}/cmake") list(APPEND CMAKE_MODULE_PATH "${CMAKE_CURRENT_SOURCE_DIR}/cmake")
set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -std=c++11 ")
set(bitness 32) set(bitness 32)
if(CMAKE_SIZEOF_VOID_P EQUAL 8) if(CMAKE_SIZEOF_VOID_P EQUAL 8)
@@ -23,11 +26,11 @@ if(WIN32 AND MSVC_VERSION LESS 1900)
message(FATAL_ERROR "Building with Microsoft compiler needs Latest Visual Studio 2015 (Community or better)") message(FATAL_ERROR "Building with Microsoft compiler needs Latest Visual Studio 2015 (Community or better)")
endif() endif()
link_directories(${LibOSRM_LIBRARY_DIRS})
add_executable(osrm-example example.cpp) add_executable(osrm-example example.cpp)
find_package(LibOSRM REQUIRED) find_package(LibOSRM REQUIRED)
find_package(Boost 1.49.0 COMPONENTS filesystem system thread iostreams REQUIRED)
target_link_libraries(osrm-example ${LibOSRM_LIBRARIES} ${Boost_LIBRARIES})
include_directories(SYSTEM ${LibOSRM_INCLUDE_DIRS} ${Boost_INCLUDE_DIRS})
target_link_libraries(osrm-example ${LibOSRM_LIBRARIES} ${LibOSRM_DEPENDENT_LIBRARIES})
include_directories(SYSTEM ${LibOSRM_INCLUDE_DIRS})
set(CMAKE_CXX_FLAGS ${LibOSRM_CXXFLAGS})
+24 -26
View File
@@ -1,13 +1,24 @@
# - Try to find LibOSRM # - Try to find LibOSRM
# Once done this will define # Once done this will define
# LibOSRM_FOUND - System has LibOSRM # LibOSRM_FOUND - System has LibOSRM
# LibOSRM_INCLUDE_DIRS - The LibOSRM include directories # LibOSRM_LIBRARIES - The libraries and ldflags needed to use LibOSRM
# LibOSRM_LIBRARIES - The libraries needed to use LibOSRM # LibOSRM_DEPENDENT_LIBRARIES - The libraries and ldflags need to link LibOSRM dependencies
# LibOSRM_DEFINITIONS - Compiler switches required for using LibOSRM # LibOSRM_LIBRARY_DIRS - The libraries paths needed to find LibOSRM
# LibOSRM_CXXFLAGS - Compiler switches required for using LibOSRM
find_package(PkgConfig) find_package(PkgConfig)
pkg_check_modules(PC_LibOSRM QUIET libosrm) pkg_search_module(PC_LibOSRM QUIET libosrm)
set(LibOSRM_DEFINITIONS ${PC_LibOSRM_CFLAGS_OTHER})
function(JOIN VALUES GLUE OUTPUT)
string (REPLACE ";" "${GLUE}" _TMP_STR "${VALUES}")
set (${OUTPUT} "${_TMP_STR}" PARENT_SCOPE)
endfunction()
list(REMOVE_ITEM PC_LibOSRM_CFLAGS " ")
JOIN("${PC_LibOSRM_CFLAGS}" " " output)
set(LibOSRM_CXXFLAGS ${output})
set(LibOSRM_LIBRARY_DIRS ${PC_LibOSRM_LIBRARY_DIRS})
find_path(LibOSRM_INCLUDE_DIR osrm/osrm.hpp find_path(LibOSRM_INCLUDE_DIR osrm/osrm.hpp
PATH_SUFFIXES osrm include/osrm include PATH_SUFFIXES osrm include/osrm include
@@ -19,8 +30,6 @@ find_path(LibOSRM_INCLUDE_DIR osrm/osrm.hpp
/opt/local /opt/local
/opt) /opt)
set(LibOSRM_INCLUDE_DIRS ${LibOSRM_INCLUDE_DIR} ${LibOSRM_INCLUDE_DIR}/osrm)
find_library(TEST_LibOSRM_STATIC_LIBRARY Names osrm.lib libosrm.a find_library(TEST_LibOSRM_STATIC_LIBRARY Names osrm.lib libosrm.a
PATH_SUFFIXES osrm lib/osrm lib PATH_SUFFIXES osrm lib/osrm lib
HINTS ${PC_LibOSRM_LIBDIR} ${PC_LibOSRM_LIBRARY_DIRS} HINTS ${PC_LibOSRM_LIBDIR} ${PC_LibOSRM_LIBRARY_DIRS}
@@ -30,7 +39,7 @@ find_library(TEST_LibOSRM_STATIC_LIBRARY Names osrm.lib libosrm.a
/usr /usr
/opt/local /opt/local
/opt) /opt)
find_library(TEST_LibOSRM_DYNAMIC_LIBRARY Names osrm.dynlib libosrm.so find_library(TEST_LibOSRM_DYNAMIC_LIBRARY Names libosrm.dylib libosrm.so
PATH_SUFFIXES osrm lib/osrm lib PATH_SUFFIXES osrm lib/osrm lib
HINTS ${PC_LibOSRM_LIBDIR} ${PC_LibOSRM_LIBRARY_DIRS} HINTS ${PC_LibOSRM_LIBDIR} ${PC_LibOSRM_LIBRARY_DIRS}
~/Library/Frameworks ~/Library/Frameworks
@@ -40,26 +49,15 @@ find_library(TEST_LibOSRM_DYNAMIC_LIBRARY Names osrm.dynlib libosrm.so
/opt/local /opt/local
/opt) /opt)
if (NOT ("${TEST_LibOSRM_STATIC_LIBRARY}" STREQUAL "TEST_LibOSRM_STATIC_LIBRARY-NOTFOUND")) set(LibOSRM_DEPENDENT_LIBRARIES ${PC_LibOSRM_STATIC_LDFLAGS})
if ("${PC_LibOSRM_STATIC_LIBRARIES}" STREQUAL "") set(LibOSRM_LIBRARIES ${PC_LibOSRM_LDFLAGS})
set(LibOSRM_STATIC_LIBRARIES ${TEST_LibOSRM_STATIC_LIBRARY})
else()
set(LibOSRM_STATIC_LIBRARIES ${PC_LibOSRM_STATIC_LIBRARIES})
endif()
set(LibOSRM_LIBRARIES ${LibOSRM_STATIC_LIBRARIES})
endif()
if (NOT ("${TEST_LibOSRM_DYNAMIC_LIBRARY}" STREQUAL "TEST_LibOSRM_DYNAMIC_LIBRARY-NOTFOUND"))
if ("${PC_LibOSRM_LIBRARIES}" STREQUAL "")
set(LibOSRM_DYNAMIC_LIBRARIES ${TEST_LibOSRM_DYNAMIC_LIBRARY})
else()
set(LibOSRM_DYNAMIC_LIBRARIES ${PC_LibOSRM_LIBRARIES})
endif()
set(LibOSRM_LIBRARIES ${LibOSRM_DYNAMIC_LIBRARIES})
endif()
include(FindPackageHandleStandardArgs) include(FindPackageHandleStandardArgs)
# handle the QUIETLY and REQUIRED arguments and set LIBOSRM_FOUND to TRUE # handle the QUIETLY and REQUIRED arguments and set LIBOSRM_FOUND to TRUE
# if all listed variables are TRUE # if all listed variables are TRUE
find_package_handle_standard_args(LibOSRM DEFAULT_MSG find_package_handle_standard_args(LibOSRM DEFAULT_MSG
LibOSRM_LIBRARIES LibOSRM_INCLUDE_DIR) LibOSRM_LIBRARY_DIRS
LibOSRM_CXXFLAGS
LibOSRM_LIBRARIES
LibOSRM_DEPENDENT_LIBRARIES
LibOSRM_INCLUDE_DIR)
+1 -1
View File
@@ -115,7 +115,7 @@ Feature: Bike - Oneway streets
Scenario: Bike - Two consecutive oneways Scenario: Bike - Two consecutive oneways
Given the node map Given the node map
| a | b | c | | a | b | | c |
And the ways And the ways
| nodes | oneway | | nodes | oneway |
+1 -1
View File
@@ -68,7 +68,7 @@ Feature: Car - Oneway streets
Scenario: Car - Two consecutive oneways Scenario: Car - Two consecutive oneways
Given the node map Given the node map
| a | b | c | | a | b | | c |
And the ways And the ways
| nodes | oneway | | nodes | oneway |
+1
View File
@@ -5,6 +5,7 @@ Feature: Car - Turn restrictions
Background: Use car routing Background: Use car routing
Given the profile "car" Given the profile "car"
Given a grid size of 200 meters
@no_turning @no_turning
Scenario: Car - No left turn Scenario: Car - No left turn
+26 -28
View File
@@ -12,19 +12,17 @@ Feature: Traffic - turn penalties
| nodes | highway | | nodes | highway |
| ad | primary | | ad | primary |
| cd | primary | | cd | primary |
| de | primary | | def | primary |
| dhk | primary | | dhk | primary |
| bf | primary | | bf | primary |
| ef | primary |
| fg | primary | | fg | primary |
| fim | primary | | fim | primary |
| jk | primary | | jk | primary |
| kl | primary | | klm | primary |
| ko | primary | | ko | primary |
| lm | primary |
| mn | primary | | mn | primary |
| mp | primary | | mp | primary |
And the profile "car" And the profile "car"
@@ -32,22 +30,22 @@ Feature: Traffic - turn penalties
Scenario: Weighting not based on turn penalty file Scenario: Weighting not based on turn penalty file
When I route I should get When I route I should get
| from | to | route | speed | time | | from | to | route | speed | time |
| a | h | ad,dhk,dhk | 63 km/h | 11.5s +-1 | | a | h | ad,dhk,dhk | 63 km/h | 11.5s +-1 |
# straight # straight
| i | g | fim,fg,fg | 59 km/h | 12s +-1 | | i | g | fim,fg,fg | 59 km/h | 12s +-1 |
# right # right
| a | e | ad,de,de | 57 km/h | 12.5s +-1 | | a | e | ad,def,def | 57 km/h | 12.5s +-1 |
# left # left
| c | g | cd,de,ef,fg,fg | 63 km/h | 23s +-1 | | c | g | cd,def,fg,fg | 63 km/h | 23s +-1 |
# double straight # double straight
| p | g | mp,fim,fg,fg | 61 km/h | 23.5s +-1 | | p | g | mp,fim,fg,fg | 61 km/h | 23.5s +-1 |
# straight-right # straight-right
| a | l | ad,dhk,kl,kl | 60 km/h | 24s +-1 | | a | l | ad,dhk,klm,klm | 60 km/h | 24s +-1 |
# straight-left # straight-left
| l | e | kl,dhk,de,de | 59 km/h | 24.5s +-1 | | l | e | klm,dhk,def,def | 59 km/h | 24.5s +-1 |
# double right # double right
| g | n | fg,fim,mn,mn | 57 km/h | 25s +-1 | | g | n | fg,fim,mn,mn | 57 km/h | 25s +-1 |
# double left # double left
Scenario: Weighting based on turn penalty file Scenario: Weighting based on turn penalty file
@@ -62,24 +60,24 @@ Feature: Traffic - turn penalties
""" """
And the contract extra arguments "--turn-penalty-file penalties.csv" And the contract extra arguments "--turn-penalty-file penalties.csv"
When I route I should get When I route I should get
| from | to | route | speed | time | | from | to | route | speed | time |
| a | h | ad,dhk,dhk | 63 km/h | 11.5s +-1 | | a | h | ad,dhk,dhk | 63 km/h | 11.5s +-1 |
# straight # straight
| i | g | fim,fg,fg | 55 km/h | 13s +-1 | | i | g | fim,fg,fg | 55 km/h | 13s +-1 |
# right - ifg penalty # right - ifg penalty
| a | e | ad,de,de | 64 km/h | 11s +-1 | | a | e | ad,def,def | 64 km/h | 11s +-1 |
# left - faster because of negative ade penalty # left - faster because of negative ade penalty
| c | g | cd,de,ef,fg,fg | 63 km/h | 23s +-1 | | c | g | cd,def,fg,fg | 63 km/h | 23s +-1 |
# double straight # double straight
| p | g | mp,fim,fg,fg | 59 km/h | 24.5s +-1 | | p | g | mp,fim,fg,fg | 59 km/h | 24.5s +-1 |
# straight-right - ifg penalty # straight-right - ifg penalty
| a | l | ad,de,ef,fim,lm,lm | 61 km/h | 35.5s +-1 | | a | l | ad,def,fim,klm,klm | 61 km/h | 35.5s +-1 |
# was straight-left - forced around by hkl penalty # was straight-left - forced around by hkl penalty
| l | e | lm,fim,ef,ef | 57 km/h | 25s +-1 | | l | e | klm,fim,def,def | 57 km/h | 25s +-1 |
# double right - forced left by lkh penalty # double right - forced left by lkh penalty
| g | n | fg,fim,mn,mn | 30 km/h | 47.5s +-1 | | g | n | fg,fim,mn,mn | 30 km/h | 47.5s +-1 |
# double left - imn penalty # double left - imn penalty
| j | c | jk,kl,lm,fim,ef,de,cd,cd | 60 km/h | 48s +-1 | | j | c | jk,klm,fim,def,cd,cd | 60 km/h | 48s +-1 |
# double left - hdc penalty ever so slightly higher than imn; forces all the way around # double left - hdc penalty ever so slightly higher than imn; forces all the way around
Scenario: Too-negative penalty clamps, but does not fail Scenario: Too-negative penalty clamps, but does not fail
@@ -90,8 +88,8 @@ Feature: Traffic - turn penalties
1,4,5,-10 1,4,5,-10
""" """
When I route I should get When I route I should get
| from | to | route | time | | from | to | route | time |
| a | d | ad,ad | 10s +-1 | | a | d | ad,ad | 10s +-1 |
| a | e | ad,de,de | 10s +-1 | | a | e | ad,def,def | 10s +-1 |
| b | f | bf,bf | 10s +-1 | | b | f | bf,bf | 10s +-1 |
| b | g | bf,fg,fg | 20s +-1 | | b | g | bf,fg,fg | 20s +-1 |
+285
View File
@@ -345,3 +345,288 @@ Feature: Collapse
| a,d | first,first,first,first | depart,continue left,continue right,arrive | | a,d | first,first,first,first | depart,continue left,continue right,arrive |
| a,e | first,second,second | depart,turn left,arrive | | a,e | first,second,second | depart,turn left,arrive |
| a,f | first,third,third | depart,turn straight,arrive | | a,f | first,third,third | depart,turn straight,arrive |
Scenario: Bridge on unnamed road
Given the node map
| a | b | | | | c | d |
And the ways
| nodes | highway | name |
| ab | primary | |
| bc | primary | Bridge |
| cd | primary | |
When I route I should get
| waypoints | route | turns |
| a,d | , | depart,arrive |
Scenario: Crossing Bridge into Segregated Turn
Given the node map
| | | | | | f |
| i | h | | | g | e |
| a | b | | | c | d |
And the ways
| nodes | highway | oneway | name |
| ab | primary | yes | to_bridge |
| bc | primary | yes | bridge |
| cd | primary | yes | off_bridge |
| de | primary | yes | |
| ef | primary | no | target_road |
| eg | primary | yes | off_bridge |
| gh | primary | yes | bridge |
| hi | primary | yes | to_bridge |
When I route I should get
| waypoints | route | turns |
| a,f | to_bridge,target_road,target_road | depart,turn left,arrive |
Scenario: Pankenbruecke
Given the node map
| h | | | | | | i | | | | | | |
| | | b | c | d | e | f | | | | | | g |
| a | | | | | | | | | | | | |
And the ways
| nodes | highway | name | oneway |
| abh | primary | inroad | yes |
| bc | primary | inroad | no |
| cd | primary | bridge | no |
| defg | primary | outroad | no |
| fi | primary | cross | no |
When I route I should get
| waypoints | route | turns |
| a,g | inroad,outroad,outroad | depart,new name straight,arrive |
| a,i | inroad,cross,cross | depart,turn left,arrive |
Scenario: Close Turns - Don't Collapse
Given the node map
| | g | d | |
| | | | |
| e | b | c | f |
| | | | |
| | a | h | |
And the ways
| nodes | highway | name |
| ab | primary | in |
| ebcf | primary | cross |
| cd | primary | out |
| bg | primary | straight |
| ch | primary | reverse |
When I route I should get
| waypoints | route | turns |
| a,d | in,cross,out,out | depart,turn right,turn left,arrive |
| a,h | in,cross,reverse,reverse | depart,turn right,turn right,arrive |
| g,d | straight,cross,out,out | depart,turn left,turn left,arrive |
Scenario: No Name During Turns
Given the node map
| a | b | |
| | c | d |
And the ways
| nodes | highway | name |
| ab | tertiary | road |
| bc | tertiary | |
| cd | tertiary | road |
When I route I should get
| waypoints | route | turns |
| a,d | road,road | depart,arrive |
Scenario: No Name During Turns, Random Oneway
Given the node map
| a | b | |
| | c | d |
And the ways
| nodes | highway | name | oneway |
| ab | tertiary | road | no |
| bc | tertiary | | yes |
| cd | tertiary | road | no |
When I route I should get
| waypoints | route | turns |
| a,d | road,road | depart,arrive |
Scenario: Pulled Back Turn
Given the node map
| | | d |
| a | b | c |
| | e | |
And the ways
| nodes | highway | name |
| abc | tertiary | road |
| cd | tertiary | left |
| be | tertiary | right |
When I route I should get
| waypoints | route | turns |
| a,d | road,left,left | depart,turn left,arrive |
| a,e | road,right,right | depart,turn right,arrive |
Scenario: No Name During Turns, keep important turns
Given the node map
| a | b | e |
| | c | d |
And the ways
| nodes | highway | name |
| ab | tertiary | road |
| bc | tertiary | |
| cd | tertiary | road |
| be | tertiary | other |
When I route I should get
| waypoints | route | turns |
| a,d | road,road,road | depart,continue right,arrive |
Scenario: Segregated Intersection into Slight Turn
Given the node map
| h | | | | | | |
| a | | | | | | |
| | | | | | | |
| | | g | | | | |
| | | b | f | | | |
| | | | c | | | |
| | | | | | | |
| | | | | | | |
| | | | | | | e |
| | | | | | | d |
| | | j | i | | | |
And the ways
| nodes | highway | name | oneway |
| abcd | primary | road | yes |
| efgh | primary | road | yes |
| icf | secondary | in | yes |
| gbj | secondary | out | yes |
When I route I should get
| waypoints | route | turns |
| i,h | in,road,road | depart,turn slight left,arrive |
| a,d | road,road | depart,arrive |
| a,j | road,out,out | depart,turn slight right,arrive |
Scenario: Don't collapse everything to u-turn / too wide
Given the node map
| a | | b | | e |
| | | | | |
| d | | c | | f |
And the ways
| nodes | highway | name |
| abcd | primary | road |
| be | secondary | top |
| cf | secondary | bottom |
When I route I should get
| waypoints | turns | route |
| a,d | depart,continue right,end of road right,arrive | road,road,road,road |
| d,a | depart,continue left,end of road left,arrive | road,road,road,road |
Scenario: Forking before a turn
Given the node map
| | | | g | |
| | | | | |
| | | | c | |
| a | | b | d | e |
| | | | | |
| | | | f | |
And the ways
| nodes | name | oneway | highway |
| ab | road | yes | primary |
| bd | road | yes | primary |
| bc | road | yes | primary |
| de | road | yes | primary |
| fdcg | cross | no | secondary |
And the relations
| type | way:from | way:to | node:via | restriction |
| restriction | bd | fdcg | d | no_left_turn |
| restriction | bc | fdcg | c | no_right_turn |
When I route I should get
| waypoints | route | turns |
| a,g | road,cross,cross | depart,turn left,arrive |
| a,e | road,road | depart,arrive |
Scenario: Forking before a turn (narrow)
Given the node map
| | | | g | |
| | | | | |
| | | | c | |
| a | b | | d | e |
| | | | | |
| | | | f | |
And the ways
| nodes | name | oneway | highway |
| ab | road | yes | primary |
| bd | road | yes | primary |
| bc | road | yes | primary |
| de | road | yes | primary |
| fdcg | cross | no | secondary |
And the relations
| type | way:from | way:to | node:via | restriction |
| restriction | bd | fdcg | d | no_left_turn |
| restriction | bc | fdcg | c | no_right_turn |
When I route I should get
| waypoints | route | turns |
| a,g | road,cross,cross | depart,turn left,arrive |
| a,e | road,road | depart,arrive |
Scenario: Forking before a turn (forky)
Given the node map
| | | | g | | |
| | | | | | |
| | | | c | | |
| a | b | | | | |
| | | | | d | |
| | | | | f | e |
And the ways
| nodes | name | oneway | highway |
| ab | road | yes | primary |
| bd | road | yes | primary |
| bc | road | yes | primary |
| de | road | yes | primary |
| fdcg | cross | no | secondary |
And the relations
| type | way:from | way:to | node:via | restriction |
| restriction | bd | fdcg | d | no_left_turn |
| restriction | bc | fdcg | c | no_right_turn |
When I route I should get
| waypoints | route | turns |
| a,g | road,cross,cross | depart,turn left,arrive |
| a,e | road,road,road | depart,continue slight right,arrive |
# We should discuss whether the next item should be collapsed to depart,turn right,arrive.
| a,f | road,road,cross,cross | depart,continue slight right,turn right,arrive |
Scenario: On-Off on Highway
Given the node map
| f | | | |
| a | b | c | d |
| | | | e |
And the ways
| nodes | name | highway | oneway |
| abcd | Hwy | motorway | yes |
| fb | on | motorway_link | yes |
| ce | off | motorway_link | yes |
When I route I should get
| waypoints | route | turns |
| a,d | Hwy,Hwy | depart,arrive |
| f,d | on,Hwy,Hwy | depart,merge slight right,arrive |
| f,e | on,Hwy,off,off | depart,merge slight right,off ramp right,arrive |
| a,e | Hwy,off,off | depart,off ramp right,arrive |
+15
View File
@@ -281,3 +281,18 @@ Feature: Fork Instructions
| a,c | abd,bc,bc | depart,turn slight left,arrive | | a,c | abd,bc,bc | depart,turn slight left,arrive |
| a,d | abd,abd | depart,arrive | | a,d | abd,abd | depart,arrive |
| a,e | abd,be,be | depart,turn slight right,arrive | | a,e | abd,be,be | depart,turn slight right,arrive |
Scenario: Don't Fork when leaving Road
Given the node map
| a | | b | | c |
| | | | | d |
And the ways
| nodes | highway |
| abc | secondary |
| bd | secondary |
When I route I should get
| waypoints | route | turns |
| a,c | abc,abc | depart,arrive |
| a,d | abc,bd,bd | depart,turn slight right,arrive |
+3 -3
View File
@@ -117,9 +117,9 @@ Feature: Intersections Data
| cf | corner | | cf | corner |
When I route I should get When I route I should get
| waypoints | route | turns | intersections | | waypoints | route | turns | intersections |
| a,d | through,through | depart,arrive | true:90,true:0 true:90 false:270,true:90 true:180 false:270;true:270 | | a,d | through,through | depart,arrive | true:90,true:0 true:90 false:270,true:90 true:180 false:270;true:270 |
| f,a | corner,throughbridge,through | depart,end of road left,arrive | true:0;true:90 false:180 true:270,true:0 false:90 true:270;true:90 | | f,a | corner,through,through | depart,end of road left,arrive | true:0;true:90 false:180 true:270,true:0 false:90 true:270;true:90 |
Scenario: Roundabouts Scenario: Roundabouts
Given the node map Given the node map
+3 -3
View File
@@ -3,7 +3,7 @@ Feature: New-Name Instructions
Background: Background:
Given the profile "car" Given the profile "car"
Given a grid size of 10 meters Given a grid size of 100 meters
Scenario: Undisturbed name Change Scenario: Undisturbed name Change
Given the node map Given the node map
@@ -136,7 +136,7 @@ Feature: New-Name Instructions
Scenario: Empty road names - Announce Change From, suppress Change To Scenario: Empty road names - Announce Change From, suppress Change To
Given the node map Given the node map
| a | | b | | c | | d | | a | | b | 1 | c | | d |
And the ways And the ways
| nodes | name | | nodes | name |
@@ -147,7 +147,7 @@ Feature: New-Name Instructions
When I route I should get When I route I should get
| waypoints | route | turns | | waypoints | route | turns |
| a,d | ab,cd,cd | depart,new name straight,arrive | | a,d | ab,cd,cd | depart,new name straight,arrive |
| a,c | ab, | depart,arrive | | a,1 | ab, | depart,arrive |
Scenario: Empty road names - Loose name shortly Scenario: Empty road names - Loose name shortly
Given the node map Given the node map
+37
View File
@@ -361,3 +361,40 @@ Feature: Basic Roundabout
| a,f | ab,ef,ef | depart,roundabout-exit-2,arrive | 0->180,180->270,180->0 | | a,f | ab,ef,ef | depart,roundabout-exit-2,arrive | 0->180,180->270,180->0 |
| a,h | ab,gh,gh | depart,roundabout-exit-1,arrive | 0->180,180->270,270->0 | | a,h | ab,gh,gh | depart,roundabout-exit-1,arrive | 0->180,180->270,270->0 |
Scenario: Motorway Roundabout
#See 39.933742 -75.082345
Given the node map
| | | | | l | | | | a | | i |
| | | | | | | | | | | |
| | | | | | | | | | | |
| | | | | | | b | | | | |
| | | | c | | | | | | | |
| | | | | | | | | | | |
| | | | | | | | | h | | |
| n | | | | | | | | | | |
| | | | | | | | | | | |
| | | d | | | | | | | | j |
| | | | | | | | | | | |
| | | | | m | | | g | | | |
| | | | | | | | | | | |
| | | | | | | | | | | |
| | | e | | f | | | | | | |
And the ways
| nodes | junction | name | highway | oneway | ref |
| ab | | crescent | trunk | yes | US 130 |
| bcd | roundabout | crescent | trunk | yes | US 130 |
| de | | crescent | trunk | yes | US 130 |
| fg | | crescent | trunk | yes | US 130 |
| gh | roundabout | crescent | trunk | yes | US 130 |
| hi | | crescent | trunk | yes | US 130 |
| jh | | | trunk_link | yes | NJ 38 |
| hb | roundabout | | trunk_link | yes | NJ 38 |
| bl | | | trunk_link | yes | NJ 38 |
| cnd | | kaighns | trunk_link | yes | |
| dmg | roundabout | | trunk_link | yes | |
When I route I should get
| waypoints | route | turns |
| a,e | crescent (US 130),crescent (US 130),crescent (US 130) | depart,roundabout-exit-3,arrive |
| j,l | NJ 38,NJ 38,NJ 38 | depart,roundabout-exit-2,arrive |
+27
View File
@@ -806,3 +806,30 @@ Feature: Simple Turns
| a,e | abc,be,be | depart,turn right,arrive | | a,e | abc,be,be | depart,turn right,arrive |
| a,f | abc,bf,bf | depart,turn slight right,arrive | | a,f | abc,bf,bf | depart,turn slight right,arrive |
Scenario: Turn Lane on Splitting up Road
Given the node map
| | | | | | | | | | | | | | | |
| g | | | | f | | | | | | | | | | |
| | | | | | | | | | | | | | | |
| | | | | | h | | | e | | | c | | | d |
| a | | | b | | | | | | | | | | | |
| | | | i | | | | | | | | | | | |
And the ways
| nodes | highway | oneway | name |
| ab | secondary | yes | road |
| be | secondary | yes | road |
| ecd | secondary | no | road |
| efg | secondary | yes | road |
| ehb | secondary_link | yes | road |
| bi | tertiary | no | cross |
And the relations
| type | way:from | way:to | node:via | restriction |
| restriction | ehb | be | b | no_left_turn |
When I route I should get
| waypoints | route | turns |
| a,d | road,road | depart,arrive |
| d,i | road,cross,cross | depart,turn left,arrive |
| d,g | road,road | depart,arrive |
+3 -2
View File
@@ -3,6 +3,7 @@ Feature: Alternative route
Background: Background:
Given the profile "testbot" Given the profile "testbot"
And a grid size of 200 meters
And the node map And the node map
| | b | c | d | | | | | b | c | d | | |
@@ -17,11 +18,11 @@ Feature: Alternative route
| dz | | dz |
| ag | | ag |
| gh | | gh |
| ck |
| kh |
| hi | | hi |
| ij | | ij |
| jz | | jz |
| ck |
| kh |
Scenario: Enabled alternative Scenario: Enabled alternative
Given the query options Given the query options
+1 -1
View File
@@ -56,7 +56,7 @@ Feature: Basic Routing
Scenario: Two ways connected in a straight line Scenario: Two ways connected in a straight line
Given the node map Given the node map
| a | b | c | | a | | b | | c |
And the ways And the ways
| nodes | | nodes |
+32 -28
View File
@@ -43,8 +43,8 @@ Feature: Bearing parameter
Scenario: Testbot - Initial bearing on split way Scenario: Testbot - Initial bearing on split way
Given the node map Given the node map
| d | | | | | 1 | | | | | c | | g | d | | | | | 1 | | | | | c | f |
| a | | | | | 0 | | | | | b | | h | a | | | | | 0 | | | | | b | e |
And the ways And the ways
| nodes | oneway | | nodes | oneway |
@@ -52,6 +52,10 @@ Feature: Bearing parameter
| bc | yes | | bc | yes |
| cd | yes | | cd | yes |
| da | yes | | da | yes |
| be | yes |
| fc | yes |
| dg | yes |
| ha | yes |
When I route I should get When I route I should get
| from | to | bearings | route | bearing | | from | to | bearings | route | bearing |
@@ -81,31 +85,31 @@ Feature: Bearing parameter
| f | | | e | | | d | | f | | | e | | | d |
And the ways And the ways
| nodes | oneway | | nodes | oneway | name |
| ia | yes | | ia | yes | ia |
| jb | yes | | jb | yes | jb |
| kc | yes | | kc | yes | kc |
| ld | yes | | ld | yes | ld |
| me | yes | | me | yes | me |
| nf | yes | | nf | yes | nf |
| og | yes | | og | yes | og |
| ph | yes | | ph | yes | ph |
| ab | yes | | ab | yes | ring |
| bc | yes | | bc | yes | ring |
| cd | yes | | cd | yes | ring |
| de | yes | | de | yes | ring |
| ef | yes | | ef | yes | ring |
| fg | yes | | fg | yes | ring |
| gh | yes | | gh | yes | ring |
| ha | yes | | ha | yes | ring |
When I route I should get When I route I should get
| from | to | bearings | route | bearing | | from | to | bearings | route | bearing |
| 0 | q | 0 90 | ia,ab,bc,cd,de,ef,fg,gh,ha,ha | 0->0,0->90,90->180,180->180,180->270,270->270,270->0,0->0,0->90,90->0 | | 0 | q | 0 90 | ia,ring,ring,ring,ring,ring | 0->0,0->90,180->270,270->0,0->90,90->0 |
| 0 | a | 45 90 | jb,bc,cd,de,ef,fg,gh,ha,ha | 0->45,45->180,180->180,180->270,270->270,270->0,0->0,0->90,90->0 | | 0 | a | 45 90 | jb,ring,ring,ring,ring,ring | 0->45,45->180,180->270,270->0,0->90,90->0 |
| 0 | q | 90 90 | kc,cd,de,ef,fg,gh,ha,ha | 0->90,90->180,180->270,270->270,270->0,0->0,0->90,90->0 | | 0 | q | 90 90 | kc,ring,ring,ring,ring | 0->90,90->180,270->0,0->90,90->0 |
| 0 | a | 135 90 | ld,de,ef,fg,gh,ha,ha | 0->135,135->270,270->270,270->0,0->0,0->90,90->0 | | 0 | a | 135 90 | ld,ring,ring,ring,ring | 0->135,135->270,270->0,0->90,90->0 |
| 0 | a | 180 90 | me,ef,fg,gh,ha,ha | 0->180,180->270,270->0,0->0,0->90,90->0 | | 0 | a | 180 90 | me,ring,ring,ring | 0->180,180->270,0->90,90->0 |
| 0 | a | 225 90 | nf,fg,gh,ha,ha | 0->225,225->0,0->0,0->90,90->0 | | 0 | a | 225 90 | nf,ring,ring,ring | 0->225,225->0,0->90,90->0 |
| 0 | a | 270 90 | og,gh,ha,ha | 0->270,270->0,0->90,90->0 | | 0 | a | 270 90 | og,ring,ring | 0->270,270->0,90->0 |
| 0 | a | 315 90 | ph,ha,ha | 0->315,315->90,90->0 | | 0 | a | 315 90 | ph,ring,ring | 0->315,315->90,90->0 |
@@ -3,6 +3,7 @@ Feature: U-turns at via points
Background: Background:
Given the profile "testbot" Given the profile "testbot"
Given a grid size of 100 meters
Scenario: Continue straight at waypoints enabled by default Scenario: Continue straight at waypoints enabled by default
Given the node map Given the node map
+4 -3
View File
@@ -11,6 +11,7 @@ Feature: Testbot - Travel mode
Background: Background:
Given the profile "testbot" Given the profile "testbot"
Given a grid size of 200 meters
Scenario: Testbot - Always announce mode change Scenario: Testbot - Always announce mode change
Given the node map Given the node map
@@ -72,9 +73,9 @@ Feature: Testbot - Travel mode
| ab | steps | | ab | steps |
When I route I should get When I route I should get
| from | to | route | modes | time | | from | to | route | modes | time |
| 0 | 1 | ab,ab | steps down,steps down | 60s +-1 | | 0 | 1 | ab,ab | steps down,steps down | 120s +-1 |
| 1 | 0 | ab,ab | steps up,steps up | 60s +-1 | | 1 | 0 | ab,ab | steps up,steps up | 120s +-1 |
@oneway @oneway
Scenario: Testbot - Modes for oneway, different forward/backward speeds Scenario: Testbot - Modes for oneway, different forward/backward speeds
+2 -1
View File
@@ -3,9 +3,10 @@ Feature: Basic Routing
Background: Background:
Given the profile "testbot" Given the profile "testbot"
Given a grid size of 200 meters
@smallest @smallest
Scenario: Checking Scenario: Checking
Given the node map Given the node map
| a | b | 1 | c | d | e | | a | b | 1 | c | d | e |
+1
View File
@@ -57,6 +57,7 @@ util::json::Object makeGeoJSONGeometry(ForwardIter begin, ForwardIter end)
{ {
geojson.values["type"] = "LineString"; geojson.values["type"] = "LineString";
util::json::Array coordinates; util::json::Array coordinates;
coordinates.values.reserve(num_coordinates);
std::transform( std::transform(
begin, end, std::back_inserter(coordinates.values), &detail::coordinateToLonLat); begin, end, std::back_inserter(coordinates.values), &detail::coordinateToLonLat);
geojson.values["coordinates"] = std::move(coordinates); geojson.values["coordinates"] = std::move(coordinates);
+9
View File
@@ -144,6 +144,7 @@ class RouteAPI : public BaseAPI
guidance::trimShortSegments(steps, leg_geometry); guidance::trimShortSegments(steps, leg_geometry);
leg.steps = guidance::postProcess(std::move(steps)); leg.steps = guidance::postProcess(std::move(steps));
leg.steps = guidance::collapseTurns(std::move(leg.steps)); leg.steps = guidance::collapseTurns(std::move(leg.steps));
leg.steps = guidance::buildIntersections(std::move(leg.steps));
leg.steps = guidance::assignRelativeLocations(std::move(leg.steps), leg.steps = guidance::assignRelativeLocations(std::move(leg.steps),
leg_geometry, leg_geometry,
phantoms.source_phantom, phantoms.source_phantom,
@@ -172,6 +173,9 @@ class RouteAPI : public BaseAPI
for (const auto idx : util::irange<std::size_t>(0UL, legs.size())) for (const auto idx : util::irange<std::size_t>(0UL, legs.size()))
{ {
auto &leg_geometry = leg_geometries[idx]; auto &leg_geometry = leg_geometries[idx];
step_geometries.reserve(step_geometries.size() + legs[idx].steps.size());
std::transform( std::transform(
legs[idx].steps.begin(), legs[idx].steps.begin(),
legs[idx].steps.end(), legs[idx].steps.end(),
@@ -200,6 +204,11 @@ class RouteAPI : public BaseAPI
util::json::Array distances; util::json::Array distances;
util::json::Array nodes; util::json::Array nodes;
auto &leg_geometry = leg_geometries[idx]; auto &leg_geometry = leg_geometries[idx];
durations.values.reserve(leg_geometry.annotations.size());
distances.values.reserve(leg_geometry.annotations.size());
nodes.values.reserve(leg_geometry.osm_node_ids.size());
std::for_each( std::for_each(
leg_geometry.annotations.begin(), leg_geometry.annotations.begin(),
leg_geometry.annotations.end(), leg_geometry.annotations.end(),
@@ -602,7 +602,7 @@ class InternalDataFacade final : public BaseDataFacade
std::string GetPronunciationForID(const unsigned name_id) const override final std::string GetPronunciationForID(const unsigned name_id) const override final
{ {
// We store the pronounciation after the name and destination of a street. // We store the pronunciation after the name and destination of a street.
// We do this to get around the street length limit of 255 which would hit // We do this to get around the street length limit of 255 which would hit
// if we concatenate these. Order (see extractor_callbacks): // if we concatenate these. Order (see extractor_callbacks):
// name (0), destination (1), pronunciation (2) // name (0), destination (1), pronunciation (2)
@@ -171,13 +171,13 @@ class SharedDataFacade final : public BaseDataFacade
coordinate_list_ptr, coordinate_list_ptr,
data_layout->num_entries[storage::SharedDataLayout::COORDINATE_LIST]); data_layout->num_entries[storage::SharedDataLayout::COORDINATE_LIST]);
auto osmnodeid_list_ptr = data_layout->GetBlockPtr<OSMNodeID>( auto osmnodeid_list_ptr = data_layout->GetBlockPtr<std::uint64_t>(
shared_memory, storage::SharedDataLayout::OSM_NODE_ID_LIST); shared_memory, storage::SharedDataLayout::OSM_NODE_ID_LIST);
m_osmnodeid_list.reset( m_osmnodeid_list.reset(
osmnodeid_list_ptr, osmnodeid_list_ptr,
data_layout->num_entries[storage::SharedDataLayout::OSM_NODE_ID_LIST]); data_layout->num_entries[storage::SharedDataLayout::OSM_NODE_ID_LIST]);
m_osmnodeid_list.set_number_of_entries(util::PackedVectorCapacity( // We (ab)use the number of coordinates here because we know we have the same amount of ids
data_layout->num_entries[storage::SharedDataLayout::OSM_NODE_ID_LIST])); m_osmnodeid_list.set_number_of_entries(data_layout->num_entries[storage::SharedDataLayout::COORDINATE_LIST]);
auto travel_mode_list_ptr = data_layout->GetBlockPtr<extractor::TravelMode>( auto travel_mode_list_ptr = data_layout->GetBlockPtr<extractor::TravelMode>(
shared_memory, storage::SharedDataLayout::TRAVEL_MODE); shared_memory, storage::SharedDataLayout::TRAVEL_MODE);
@@ -676,7 +676,7 @@ class SharedDataFacade final : public BaseDataFacade
std::string GetPronunciationForID(const unsigned name_id) const override final std::string GetPronunciationForID(const unsigned name_id) const override final
{ {
// We store the pronounciation after the name and destination of a street. // We store the pronunciation after the name and destination of a street.
// We do this to get around the street length limit of 255 which would hit // We do this to get around the street length limit of 255 which would hit
// if we concatenate these. Order (see extractor_callbacks): // if we concatenate these. Order (see extractor_callbacks):
// name (0), destination (1), pronunciation (2) // name (0), destination (1), pronunciation (2)
@@ -133,6 +133,7 @@ std::vector<RouteStep> assembleSteps(const DataFacadeT &facade,
intersection.out = bearing_class.findMatchingBearing(bearings.second); intersection.out = bearing_class.findMatchingBearing(bearings.second);
intersection.location = facade.GetCoordinateOfNode(path_point.turn_via_node); intersection.location = facade.GetCoordinateOfNode(path_point.turn_via_node);
intersection.bearings.clear(); intersection.bearings.clear();
intersection.bearings.reserve(bearing_class.getAvailableBearings().size());
std::copy(bearing_class.getAvailableBearings().begin(), std::copy(bearing_class.getAvailableBearings().begin(),
bearing_class.getAvailableBearings().end(), bearing_class.getAvailableBearings().end(),
std::back_inserter(intersection.bearings)); std::back_inserter(intersection.bearings));
@@ -37,6 +37,9 @@ std::vector<RouteStep> assignRelativeLocations(std::vector<RouteStep> steps,
const PhantomNode &source_node, const PhantomNode &source_node,
const PhantomNode &target_node); const PhantomNode &target_node);
// collapse suppressed instructions remaining into intersections array
std::vector<RouteStep> buildIntersections(std::vector<RouteStep> steps);
// remove steps invalidated by post-processing // remove steps invalidated by post-processing
std::vector<RouteStep> removeNoTurnInstructions(std::vector<RouteStep> steps); std::vector<RouteStep> removeNoTurnInstructions(std::vector<RouteStep> steps);
+4 -18
View File
@@ -280,20 +280,6 @@ inline double getTurnConfidence(const double angle, TurnInstruction instruction)
return 1.0 - (difference / max_deviation) * (difference / max_deviation); return 1.0 - (difference / max_deviation) * (difference / max_deviation);
} }
// swaps left <-> right modifier types
inline DirectionModifier::Enum mirrorDirectionModifier(const DirectionModifier::Enum modifier)
{
const constexpr DirectionModifier::Enum results[] = {DirectionModifier::UTurn,
DirectionModifier::SharpLeft,
DirectionModifier::Left,
DirectionModifier::SlightLeft,
DirectionModifier::Straight,
DirectionModifier::SlightRight,
DirectionModifier::Right,
DirectionModifier::SharpRight};
return results[modifier];
}
inline bool canBeSuppressed(const TurnType::Enum type) inline bool canBeSuppressed(const TurnType::Enum type)
{ {
if (type == TurnType::Turn) if (type == TurnType::Turn)
@@ -419,10 +405,10 @@ inline bool requiresNameAnnounced(const std::string &from,
(from_ref.find(to_ref) != std::string::npos || to_ref.find(from_ref) != std::string::npos); (from_ref.find(to_ref) != std::string::npos || to_ref.find(from_ref) != std::string::npos);
const auto ref_is_removed = !from_ref.empty() && to_ref.empty(); const auto ref_is_removed = !from_ref.empty() && to_ref.empty();
const auto obvious_change = (names_are_empty && refs_are_empty) || const auto obvious_change =
(names_are_equal && ref_is_contained) || (names_are_empty && refs_are_empty) || (names_are_equal && ref_is_contained) ||
(names_are_equal && refs_are_empty) || name_is_removed || (names_are_equal && refs_are_empty) || (ref_is_contained && name_is_removed) ||
ref_is_removed || is_suffix_change; (names_are_equal && ref_is_removed) || is_suffix_change;
return !obvious_change; return !obvious_change;
} }
+16
View File
@@ -49,6 +49,22 @@ inline extractor::guidance::DirectionModifier::Enum getTurnDirection(const doubl
return extractor::guidance::DirectionModifier::UTurn; return extractor::guidance::DirectionModifier::UTurn;
} }
// swaps left <-> right modifier types
inline extractor::guidance::DirectionModifier::Enum
mirrorDirectionModifier(const extractor::guidance::DirectionModifier::Enum modifier)
{
const constexpr extractor::guidance::DirectionModifier::Enum results[] = {
extractor::guidance::DirectionModifier::UTurn,
extractor::guidance::DirectionModifier::SharpLeft,
extractor::guidance::DirectionModifier::Left,
extractor::guidance::DirectionModifier::SlightLeft,
extractor::guidance::DirectionModifier::Straight,
extractor::guidance::DirectionModifier::SlightRight,
extractor::guidance::DirectionModifier::Right,
extractor::guidance::DirectionModifier::SharpRight};
return results[modifier];
}
} // namespace guidance } // namespace guidance
} // namespace util } // namespace util
} // namespace osrm } // namespace osrm
+22 -25
View File
@@ -12,26 +12,6 @@ namespace osrm
namespace util namespace util
{ {
const constexpr std::size_t BITSIZE = 33;
const constexpr std::size_t ELEMSIZE = 64;
const constexpr std::size_t PACKSIZE = BITSIZE * ELEMSIZE;
/**
* Returns the size of the packed vector datastructure with `elements` packed elements (the size of
* its underlying vector)
*/
inline std::size_t PackedVectorSize(std::size_t elements)
{
return ceil(float(elements) / ELEMSIZE) * BITSIZE;
};
/**
* Returns the capacity of a packed vector with underlying vector size `vec_size`
*/
inline std::size_t PackedVectorCapacity(std::size_t vec_size)
{
return floor(float(vec_size) / BITSIZE) * ELEMSIZE;
}
/** /**
* Since OSM node IDs are (at the time of writing) not quite yet overflowing 32 bits, and * Since OSM node IDs are (at the time of writing) not quite yet overflowing 32 bits, and
@@ -41,9 +21,23 @@ inline std::size_t PackedVectorCapacity(std::size_t vec_size)
* NOTE: this type is templated for future use, but will require a slight refactor to * NOTE: this type is templated for future use, but will require a slight refactor to
* configure BITSIZE and ELEMSIZE * configure BITSIZE and ELEMSIZE
*/ */
template <typename T, bool UseSharedMemory> class PackedVector template <typename T, bool UseSharedMemory=false> class PackedVector
{ {
static const constexpr std::size_t BITSIZE = 33;
static const constexpr std::size_t ELEMSIZE = 64;
static const constexpr std::size_t PACKSIZE = BITSIZE * ELEMSIZE;
public: public:
/**
* Returns the size of the packed vector datastructure with `elements` packed elements (the size of
* its underlying uint64 vector)
*/
inline static std::size_t elements_to_blocks(std::size_t elements)
{
return std::ceil(static_cast<double>(elements) * BITSIZE / ELEMSIZE);
}
void push_back(T incoming_node_id) void push_back(T incoming_node_id)
{ {
std::uint64_t node_id = static_cast<std::uint64_t>(incoming_node_id); std::uint64_t node_id = static_cast<std::uint64_t>(incoming_node_id);
@@ -130,14 +124,14 @@ template <typename T, bool UseSharedMemory> class PackedVector
template <bool enabled = UseSharedMemory> template <bool enabled = UseSharedMemory>
void reserve(typename std::enable_if<!enabled, std::size_t>::type capacity) void reserve(typename std::enable_if<!enabled, std::size_t>::type capacity)
{ {
vec.reserve(PackedVectorSize(capacity)); vec.reserve(elements_to_blocks(capacity));
} }
template <bool enabled = UseSharedMemory> template <bool enabled = UseSharedMemory>
void reset(typename std::enable_if<enabled, T>::type *ptr, void reset(typename std::enable_if<enabled, std::uint64_t>::type *ptr,
typename std::enable_if<enabled, std::size_t>::type size) typename std::enable_if<enabled, std::size_t>::type size)
{ {
vec.reset(reinterpret_cast<std::uint64_t *>(ptr), size); vec.reset(ptr, size);
} }
template <bool enabled = UseSharedMemory> template <bool enabled = UseSharedMemory>
@@ -146,7 +140,10 @@ template <typename T, bool UseSharedMemory> class PackedVector
num_elements = count; num_elements = count;
} }
std::size_t capacity() const { return PackedVectorCapacity(vec.capacity()); } std::size_t capacity() const
{
return std::floor(static_cast<double>(vec.capacity()) * ELEMSIZE / BITSIZE);
}
private: private:
typename util::ShM<std::uint64_t, UseSharedMemory>::vector vec; typename util::ShM<std::uint64_t, UseSharedMemory>::vector vec;
+254 -118
View File
@@ -1,5 +1,5 @@
#include "engine/guidance/post_processing.hpp"
#include "extractor/guidance/turn_instruction.hpp" #include "extractor/guidance/turn_instruction.hpp"
#include "engine/guidance/post_processing.hpp"
#include "engine/guidance/assemble_steps.hpp" #include "engine/guidance/assemble_steps.hpp"
#include "engine/guidance/toolkit.hpp" #include "engine/guidance/toolkit.hpp"
@@ -31,35 +31,89 @@ namespace guidance
namespace namespace
{ {
const constexpr double MAX_COLLAPSE_DISTANCE = 25;
inline bool choiceless(const RouteStep &step, const RouteStep &previous)
{
// if the next turn is choiceless, we consider longer turn roads collapsable than usually
// accepted. We might need to improve this to find out whether we merge onto a through-street.
return previous.distance < 3 * MAX_COLLAPSE_DISTANCE &&
1 >= std::count(step.intersections.front().entry.begin(),
step.intersections.front().entry.end(),
true);
}
// List of types that can be collapsed, if all other restrictions pass
bool isCollapsableInstruction(const TurnInstruction instruction)
{
return instruction.type == TurnType::NewName ||
(instruction.type == TurnType::Suppressed &&
instruction.direction_modifier == DirectionModifier::Straight) ||
(instruction.type == TurnType::Turn &&
instruction.direction_modifier == DirectionModifier::Straight) ||
(instruction.type == TurnType::Continue &&
instruction.direction_modifier == DirectionModifier::Straight) ||
(instruction.type == TurnType::Merge);
}
// A check whether two instructions can be treated as one. This is only the case for very short
// maneuvers that can, in some form, be seen as one. The additional in_step is to find out about
// a possible u-turn.
bool collapsable(const RouteStep &step)
{
return step.distance < MAX_COLLAPSE_DISTANCE &&
isCollapsableInstruction(step.maneuver.instruction);
}
bool compatible(const RouteStep &lhs, const RouteStep &rhs) { return lhs.mode == rhs.mode; }
double nameSegmentLength(std::size_t at, const std::vector<RouteStep> &steps)
{
double result = steps[at].distance;
while (at + 1 < steps.size() && steps[at + 1].name_id == steps[at].name_id)
{
++at;
result += steps[at].distance;
}
return result;
}
// invalidate a step and set its content to nothing // invalidate a step and set its content to nothing
void invalidateStep(RouteStep &step) { step = getInvalidRouteStep(); } void invalidateStep(RouteStep &step) { step = getInvalidRouteStep(); }
void print(const RouteStep &step)
{
std::cout << static_cast<int>(step.maneuver.instruction.type) << " "
<< static_cast<int>(step.maneuver.instruction.direction_modifier) << " "
<< static_cast<int>(step.maneuver.waypoint_type) << " Duration: " << step.duration
<< " Distance: " << step.distance << " Geometry: " << step.geometry_begin << " "
<< step.geometry_end << " exit: " << step.maneuver.exit
<< " Intersections: " << step.intersections.size() << " [";
for (const auto &intersection : step.intersections)
{
std::cout << "(bearings:";
for (auto bearing : intersection.bearings)
std::cout << " " << bearing;
std::cout << ", entry: ";
for (auto entry : intersection.entry)
std::cout << " " << entry;
std::cout << ")";
}
std::cout << "] name[" << step.name_id << "]: " << step.name;
}
void print(const std::vector<RouteStep> &steps) void print(const std::vector<RouteStep> &steps)
{ {
std::cout << "Path\n"; std::cout << "Path\n";
int segment = 0; int segment = 0;
for (const auto &step : steps) for (const auto &step : steps)
{ {
std::cout << "\t[" << ++segment << "]: " << static_cast<int>(step.maneuver.instruction.type) std::cout << "\t[" << segment++ << "]: ";
<< " " << static_cast<int>(step.maneuver.instruction.direction_modifier) << " " print(step);
<< static_cast<int>(step.maneuver.waypoint_type) << " Duration: " << step.duration std::cout << std::endl;
<< " Distance: " << step.distance << " Geometry: " << step.geometry_begin << " "
<< step.geometry_end << " exit: " << step.maneuver.exit
<< " Intersections: " << step.intersections.size() << " [";
for (const auto &intersection : step.intersections)
{
std::cout << "(bearings:";
for (auto bearing : intersection.bearings)
std::cout << " " << bearing;
std::cout << ", entry: ";
for (auto entry : intersection.entry)
std::cout << " " << entry;
std::cout << ")";
}
std::cout << "] name[" << step.name_id << "]: " << step.name << std::endl;
} }
} }
@@ -211,7 +265,9 @@ void closeOffRoundabout(const bool on_roundabout,
// instruction and move it right to the beginning to make sure to immediately announce the // instruction and move it right to the beginning to make sure to immediately announce the
// exit. // exit.
BOOST_ASSERT(leavesRoundabout(steps[1].maneuver.instruction) || BOOST_ASSERT(leavesRoundabout(steps[1].maneuver.instruction) ||
steps[1].maneuver.instruction.type == TurnType::StayOnRoundabout); steps[1].maneuver.instruction.type == TurnType::StayOnRoundabout ||
steps[1].maneuver.instruction.type == TurnType::Suppressed ||
steps[1].maneuver.instruction.type == TurnType::NoTurn);
steps[0].geometry_end = 1; steps[0].geometry_end = 1;
steps[1] = forwardInto(steps[1], steps[0]); steps[1] = forwardInto(steps[1], steps[0]);
steps[0].duration = 0; steps[0].duration = 0;
@@ -327,15 +383,6 @@ RouteStep elongate(RouteStep step, const RouteStep &by_step)
return step; return step;
} }
// A check whether two instructions can be treated as one. This is only the case for very short
// maneuvers that can, in some form, be seen as one. The additional in_step is to find out about
// a possible u-turn.
bool collapsable(const RouteStep &step)
{
const constexpr double MAX_COLLAPSE_DISTANCE = 25;
return step.distance < MAX_COLLAPSE_DISTANCE;
}
void collapseTurnAt(std::vector<RouteStep> &steps, void collapseTurnAt(std::vector<RouteStep> &steps,
const std::size_t two_back_index, const std::size_t two_back_index,
const std::size_t one_back_index, const std::size_t one_back_index,
@@ -353,46 +400,81 @@ void collapseTurnAt(std::vector<RouteStep> &steps,
}; };
BOOST_ASSERT(!one_back_step.intersections.empty() && !current_step.intersections.empty()); BOOST_ASSERT(!one_back_step.intersections.empty() && !current_step.intersections.empty());
const auto isCollapsableInstruction = [](const TurnInstruction instruction) {
return instruction.type == TurnType::NewName ||
(instruction.type == TurnType::Turn &&
instruction.direction_modifier == DirectionModifier::Straight);
};
// Very Short New Name // Very Short New Name
if (isCollapsableInstruction(one_back_step.maneuver.instruction)) if (((collapsable(one_back_step) ||
(isCollapsableInstruction(one_back_step.maneuver.instruction) &&
choiceless(current_step, one_back_step))) &&
!(one_back_step.maneuver.instruction.type == TurnType::Merge)))
// the check against merge is a workaround for motorways
{ {
BOOST_ASSERT(two_back_index < steps.size()); BOOST_ASSERT(two_back_index < steps.size());
if (one_back_step.mode == steps[two_back_index].mode) if (compatible(one_back_step, steps[two_back_index]))
{ {
BOOST_ASSERT(!one_back_step.intersections.empty());
if (TurnType::Continue == current_step.maneuver.instruction.type ||
TurnType::Suppressed == current_step.maneuver.instruction.type)
steps[step_index].maneuver.instruction.type = TurnType::Turn;
else if (TurnType::Merge == current_step.maneuver.instruction.type)
{
steps[step_index].maneuver.instruction.direction_modifier =
util::guidance::mirrorDirectionModifier(
steps[step_index].maneuver.instruction.direction_modifier);
steps[step_index].maneuver.instruction.type = TurnType::Turn;
}
else if (TurnType::NewName == current_step.maneuver.instruction.type &&
current_step.maneuver.instruction.direction_modifier !=
DirectionModifier::Straight &&
one_back_step.intersections.front().bearings.size() > 2)
steps[step_index].maneuver.instruction.type = TurnType::Turn;
steps[two_back_index] = elongate(std::move(steps[two_back_index]), one_back_step); steps[two_back_index] = elongate(std::move(steps[two_back_index]), one_back_step);
// If the previous instruction asked to continue, the name change will have to // If the previous instruction asked to continue, the name change will have to
// be changed into a turn // be changed into a turn
invalidateStep(steps[one_back_index]); invalidateStep(steps[one_back_index]);
if (TurnType::Continue == current_step.maneuver.instruction.type)
steps[step_index].maneuver.instruction.type = TurnType::Turn;
} }
} }
// very short segment after turn // very short segment after turn
else if (isCollapsableInstruction(current_step.maneuver.instruction)) else if (one_back_step.distance <= MAX_COLLAPSE_DISTANCE &&
isCollapsableInstruction(current_step.maneuver.instruction))
{ {
if (one_back_step.mode == current_step.mode) if (compatible(one_back_step, current_step))
{ {
steps[step_index] = elongate(std::move(steps[step_index]), steps[one_back_index]); steps[one_back_index] = elongate(std::move(steps[one_back_index]), steps[step_index]);
invalidateStep(steps[one_back_index]); if ((TurnType::Continue == one_back_step.maneuver.instruction.type ||
TurnType::Suppressed == one_back_step.maneuver.instruction.type) &&
if (TurnType::Continue == current_step.maneuver.instruction.type) current_step.name_id != steps[two_back_index].name_id)
{ {
steps[step_index].maneuver.instruction.type = TurnType::Turn; steps[one_back_index].maneuver.instruction.type = TurnType::Turn;
} }
else if (TurnType::Turn == one_back_step.maneuver.instruction.type &&
current_step.name_id == steps[two_back_index].name_id)
{
steps[one_back_index].maneuver.instruction.type = TurnType::Continue;
}
else if (TurnType::Merge == one_back_step.maneuver.instruction.type &&
current_step.maneuver.instruction.type !=
TurnType::Suppressed) // This suppressed is a check for highways. We might
// need a highway-suppressed to get the turn onto a
// highway...
{
steps[one_back_index].maneuver.instruction.direction_modifier =
util::guidance::mirrorDirectionModifier(
steps[one_back_index].maneuver.instruction.direction_modifier);
}
steps[one_back_index].name = current_step.name;
steps[one_back_index].name_id = current_step.name_id;
invalidateStep(steps[step_index]);
} }
} }
// Potential U-Turn // Potential U-Turn
else if (bearingsAreReversed(util::bearing::reverseBearing( else if ((one_back_step.distance <= MAX_COLLAPSE_DISTANCE ||
choiceless(current_step, one_back_step)) &&
bearingsAreReversed(util::bearing::reverseBearing(
one_back_step.intersections.front() one_back_step.intersections.front()
.bearings[one_back_step.intersections.front().in]), .bearings[one_back_step.intersections.front().in]),
current_step.intersections.front() current_step.intersections.front()
.bearings[current_step.intersections.front().out])) .bearings[current_step.intersections.front().out]) &&
compatible(one_back_step, current_step))
{ {
BOOST_ASSERT(two_back_index < steps.size()); BOOST_ASSERT(two_back_index < steps.size());
@@ -405,8 +487,7 @@ void collapseTurnAt(std::vector<RouteStep> &steps,
(step_index + 1 < steps.size()) && (step_index + 1 < steps.size()) &&
isCollapsableInstruction(steps[step_index + 1].maneuver.instruction); isCollapsableInstruction(steps[step_index + 1].maneuver.instruction);
const bool u_turn_with_name_change = const bool u_turn_with_name_change =
collapsable(current_step) && continues_with_name_change && continues_with_name_change && steps[step_index + 1].name == steps[two_back_index].name;
steps[step_index + 1].name == steps[two_back_index].name;
if (direct_u_turn || u_turn_with_name_change) if (direct_u_turn || u_turn_with_name_change)
{ {
@@ -484,14 +565,12 @@ std::vector<RouteStep> postProcess(std::vector<RouteStep> steps)
// required. We might end up with only one of them (e.g. starting within a roundabout) // required. We might end up with only one of them (e.g. starting within a roundabout)
// or having a via-point in the roundabout. // or having a via-point in the roundabout.
// In this case, exits are numbered from the start of the lag. // In this case, exits are numbered from the start of the lag.
std::size_t last_valid_instruction = 0;
for (std::size_t step_index = 0; step_index < steps.size(); ++step_index) for (std::size_t step_index = 0; step_index < steps.size(); ++step_index)
{ {
auto &step = steps[step_index]; auto &step = steps[step_index];
const auto instruction = step.maneuver.instruction; const auto instruction = step.maneuver.instruction;
if (entersRoundabout(instruction)) if (entersRoundabout(instruction))
{ {
last_valid_instruction = step_index;
has_entered_roundabout = setUpRoundabout(step); has_entered_roundabout = setUpRoundabout(step);
if (has_entered_roundabout && step_index + 1 < steps.size()) if (has_entered_roundabout && step_index + 1 < steps.size())
@@ -512,24 +591,11 @@ std::vector<RouteStep> postProcess(std::vector<RouteStep> steps)
// in case the we are not on a roundabout, the very first instruction // in case the we are not on a roundabout, the very first instruction
// after the depart will be transformed into a roundabout and become // after the depart will be transformed into a roundabout and become
// the first valid instruction // the first valid instruction
last_valid_instruction = 1;
} }
closeOffRoundabout(has_entered_roundabout, steps, step_index); closeOffRoundabout(has_entered_roundabout, steps, step_index);
has_entered_roundabout = false; has_entered_roundabout = false;
on_roundabout = false; on_roundabout = false;
} }
else if (instruction.type == TurnType::Suppressed)
{
// count intersections. We cannot use exit, since intersections can follow directly
// after a roundabout
steps[last_valid_instruction] = elongate(steps[last_valid_instruction], step);
step.maneuver.instruction = TurnInstruction::NO_TURN();
}
else if (!isSilent(instruction))
{
// Remember the last non silent instruction
last_valid_instruction = step_index;
}
} }
// unterminated roundabout // unterminated roundabout
@@ -564,58 +630,59 @@ std::vector<RouteStep> collapseTurns(std::vector<RouteStep> steps)
BOOST_ASSERT(index > 0); BOOST_ASSERT(index > 0);
BOOST_ASSERT(index < steps.size()); BOOST_ASSERT(index < steps.size());
--index; --index;
while (index > 0 && steps[index].maneuver.instruction == TurnInstruction::NO_TURN()) while (index > 0 && steps[index].maneuver.instruction.type == TurnType::NoTurn)
--index; --index;
return index; return index;
}; };
// Check for an initial unwanted new-name const auto getPreviousNameIndex = [&steps](std::size_t index) {
{ BOOST_ASSERT(index > 0);
const auto &current_step = steps[1]; BOOST_ASSERT(index < steps.size());
if (TurnType::NewName == current_step.maneuver.instruction.type && --index; // make sure to skip the current name
current_step.name == steps[0].name) while (index > 0 && steps[index].name_id == EMPTY_NAMEID)
{ {
steps[0] = elongate(std::move(steps[0]), steps[1]); --index;
invalidateStep(steps[1]);
} }
} return index;
const auto isCollapsableInstruction = [](const TurnInstruction instruction) {
return instruction.type == TurnType::NewName ||
(instruction.type == TurnType::Turn &&
instruction.direction_modifier == DirectionModifier::Straight);
}; };
// Special case handling: if the phantomnode landed on a sliproad, we // a series of turns is only possible to collapse if its only name changes and suppressed turns.
// change this into a 'turn' instruction. Sliproads are small ramps const auto canCollapseAll = [&steps](std::size_t index, const std::size_t end_index) {
// between roads, not ramps. BOOST_ASSERT(end_index <= steps.size());
if (steps.size() >= 3 && for (; index < end_index; ++index)
steps[steps.size() - 2].maneuver.instruction.type == TurnType::Sliproad) {
{ if (steps[index].maneuver.instruction.type != TurnType::Suppressed &&
steps[steps.size() - 2].maneuver.instruction.type = TurnType::Turn; steps[index].maneuver.instruction.type != TurnType::NewName)
} return false;
}
return true;
};
// first and last instructions are waypoints that cannot be collapsed // first and last instructions are waypoints that cannot be collapsed
for (std::size_t step_index = 2; step_index < steps.size(); ++step_index) for (std::size_t step_index = 1; step_index + 1 < steps.size(); ++step_index)
{ {
const auto &current_step = steps[step_index]; const auto &current_step = steps[step_index];
if (current_step.maneuver.instruction.type == TurnType::NoTurn)
continue;
const auto one_back_index = getPreviousIndex(step_index); const auto one_back_index = getPreviousIndex(step_index);
BOOST_ASSERT(one_back_index < steps.size()); BOOST_ASSERT(one_back_index < steps.size());
// cannot collapse the depart instruction
if (one_back_index == 0 || current_step.maneuver.instruction == TurnInstruction::NO_TURN())
continue;
const auto &one_back_step = steps[one_back_index]; const auto &one_back_step = steps[one_back_index];
const auto two_back_index = getPreviousIndex(one_back_index); // how long has a name change to be so that we announce it, even as a bridge?
BOOST_ASSERT(two_back_index < steps.size()); const constexpr auto name_segment_cutoff_length = 100;
const auto isBasicNameChange = [](const RouteStep &step) {
return step.intersections.size() == 1 &&
step.intersections.front().bearings.size() == 2 &&
DirectionModifier::Straight == step.maneuver.instruction.direction_modifier;
};
// Handle sliproads from motorways in urban areas // Handle sliproads from motorways in urban areas, save from modifying depart, since
// TurnType::Sliproad != TurnType::NoTurn
if (one_back_step.maneuver.instruction.type == TurnType::Sliproad) if (one_back_step.maneuver.instruction.type == TurnType::Sliproad)
{ {
// Handle possible u-turns between highways that look like slip-roads // Handle possible u-turns between highways that look like slip-roads
if (steps[two_back_index].name_id == steps[step_index].name_id && if (steps[getPreviousIndex(one_back_index)].name_id == steps[step_index].name_id &&
steps[step_index].name_id != EMPTY_NAMEID) steps[step_index].name_id != EMPTY_NAMEID)
{ {
steps[one_back_index].maneuver.instruction.type = TurnType::Continue; steps[one_back_index].maneuver.instruction.type = TurnType::Continue;
@@ -624,42 +691,57 @@ std::vector<RouteStep> collapseTurns(std::vector<RouteStep> steps)
{ {
steps[one_back_index].maneuver.instruction.type = TurnType::Turn; steps[one_back_index].maneuver.instruction.type = TurnType::Turn;
} }
steps[one_back_index] = elongate(std::move(steps[one_back_index]), steps[step_index]); if (compatible(one_back_step, current_step))
steps[one_back_index].name_id = steps[step_index].name_id; {
steps[one_back_index].name = steps[step_index].name; steps[one_back_index] =
elongate(std::move(steps[one_back_index]), steps[step_index]);
steps[one_back_index].name_id = steps[step_index].name_id;
steps[one_back_index].name = steps[step_index].name;
const auto exit_intersection = steps[step_index].intersections.front(); const auto exit_intersection = steps[step_index].intersections.front();
const auto exit_bearing = exit_intersection.bearings[exit_intersection.out]; const auto exit_bearing = exit_intersection.bearings[exit_intersection.out];
const auto entry_intersection = steps[one_back_index].intersections.front(); const auto entry_intersection = steps[one_back_index].intersections.front();
const auto entry_bearing = entry_intersection.bearings[entry_intersection.in]; const auto entry_bearing = entry_intersection.bearings[entry_intersection.in];
const double angle = const double angle =
turn_angle(util::bearing::reverseBearing(entry_bearing), exit_bearing); turn_angle(util::bearing::reverseBearing(entry_bearing), exit_bearing);
steps[one_back_index].maneuver.instruction.direction_modifier = steps[one_back_index].maneuver.instruction.direction_modifier =
::osrm::util::guidance::getTurnDirection(angle); ::osrm::util::guidance::getTurnDirection(angle);
invalidateStep(steps[step_index]); invalidateStep(steps[step_index]);
}
} }
// Due to empty segments, we can get name-changes from A->A // Due to empty segments, we can get name-changes from A->A
// These have to be handled in post-processing // These have to be handled in post-processing
else if (isCollapsableInstruction(current_step.maneuver.instruction) && else if (isCollapsableInstruction(current_step.maneuver.instruction) &&
current_step.name == steps[one_back_index].name) current_step.maneuver.instruction.type != TurnType::Suppressed &&
steps[getPreviousNameIndex(step_index)].name == current_step.name &&
canCollapseAll(getPreviousNameIndex(step_index) + 1, step_index + 1))
{ {
steps[one_back_index] = elongate(std::move(steps[one_back_index]), steps[step_index]); BOOST_ASSERT(step_index > 0);
invalidateStep(steps[step_index]); const std::size_t last_available_name_index = getPreviousNameIndex(step_index);
for (std::size_t index = last_available_name_index + 1; index <= step_index; ++index)
{
steps[last_available_name_index] =
elongate(std::move(steps[last_available_name_index]), steps[index]);
invalidateStep(steps[index]);
}
} }
// If we look at two consecutive name changes, we can check for a name oszillation. // If we look at two consecutive name changes, we can check for a name oszillation.
// A name oszillation changes from name A shortly to name B and back to A. // A name oszillation changes from name A shortly to name B and back to A.
// In these cases, the name change will be suppressed. // In these cases, the name change will be suppressed.
else if (isCollapsableInstruction(current_step.maneuver.instruction) && else if (one_back_index > 0 && compatible(current_step, one_back_step) &&
isCollapsableInstruction(current_step.maneuver.instruction) &&
isCollapsableInstruction(one_back_step.maneuver.instruction)) isCollapsableInstruction(one_back_step.maneuver.instruction))
{ {
// valid due to step_index starting at 2 const auto two_back_index = getPreviousIndex(one_back_index);
BOOST_ASSERT(two_back_index < steps.size());
// valid, since one_back is collapsable:
const auto &coming_from_name = steps[two_back_index].name; const auto &coming_from_name = steps[two_back_index].name;
if (current_step.name == coming_from_name) if (current_step.name == coming_from_name)
{ {
if (current_step.mode == one_back_step.mode && if (compatible(one_back_step, steps[two_back_index]))
one_back_step.mode == steps[two_back_index].mode)
{ {
steps[two_back_index] = steps[two_back_index] =
elongate(elongate(std::move(steps[two_back_index]), steps[one_back_index]), elongate(elongate(std::move(steps[two_back_index]), steps[one_back_index]),
@@ -670,14 +752,46 @@ std::vector<RouteStep> collapseTurns(std::vector<RouteStep> steps)
// TODO discuss: we could think about changing the new-name to a pure notification // TODO discuss: we could think about changing the new-name to a pure notification
// about mode changes // about mode changes
} }
else if (nameSegmentLength(one_back_index, steps) < name_segment_cutoff_length &&
isBasicNameChange(one_back_step) && isBasicNameChange(current_step))
{
steps[two_back_index] =
elongate(std::move(steps[two_back_index]), steps[one_back_index]);
invalidateStep(steps[one_back_index]);
if (nameSegmentLength(step_index, steps) < name_segment_cutoff_length)
{
steps[two_back_index] =
elongate(std::move(steps[two_back_index]), steps[step_index]);
invalidateStep(steps[step_index]);
}
}
else if (choiceless(current_step, one_back_step) ||
one_back_step.distance <= MAX_COLLAPSE_DISTANCE)
{
// check for one of the multiple collapse scenarios and, if possible, collapse the
// turn
const auto two_back_index = getPreviousIndex(one_back_index);
BOOST_ASSERT(two_back_index < steps.size());
collapseTurnAt(steps, two_back_index, one_back_index, step_index);
}
} }
else if (collapsable(one_back_step)) else if (one_back_index > 0 && (one_back_step.distance <= MAX_COLLAPSE_DISTANCE ||
choiceless(current_step, one_back_step)))
{ {
// check for one of the multiple collapse scenarios and, if possible, collapse the turn // check for one of the multiple collapse scenarios and, if possible, collapse the turn
const auto two_back_index = getPreviousIndex(one_back_index);
BOOST_ASSERT(two_back_index < steps.size());
collapseTurnAt(steps, two_back_index, one_back_index, step_index); collapseTurnAt(steps, two_back_index, one_back_index, step_index);
} }
} }
// handle final sliproad
if (steps.size() >= 3 &&
steps[steps.size() - 2].maneuver.instruction.type == TurnType::Sliproad)
{
steps[steps.size() - 2].maneuver.instruction.type = TurnType::Turn;
}
BOOST_ASSERT(steps.front().intersections.size() >= 1); BOOST_ASSERT(steps.front().intersections.size() >= 1);
BOOST_ASSERT(steps.front().intersections.front().bearings.size() == 1); BOOST_ASSERT(steps.front().intersections.front().bearings.size() == 1);
BOOST_ASSERT(steps.front().intersections.front().entry.size() == 1); BOOST_ASSERT(steps.front().intersections.front().entry.size() == 1);
@@ -700,7 +814,6 @@ std::vector<RouteStep> collapseTurns(std::vector<RouteStep> steps)
// usually not be as relevant. // usually not be as relevant.
void trimShortSegments(std::vector<RouteStep> &steps, LegGeometry &geometry) void trimShortSegments(std::vector<RouteStep> &steps, LegGeometry &geometry)
{ {
if (steps.size() < 2 || geometry.locations.size() <= 2) if (steps.size() < 2 || geometry.locations.size() <= 2)
return; return;
@@ -955,6 +1068,29 @@ LegGeometry resyncGeometry(LegGeometry leg_geometry, const std::vector<RouteStep
return leg_geometry; return leg_geometry;
} }
std::vector<RouteStep> buildIntersections(std::vector<RouteStep> steps)
{
std::size_t last_valid_instruction = 0;
for (std::size_t step_index = 0; step_index < steps.size(); ++step_index)
{
auto &step = steps[step_index];
const auto instruction = step.maneuver.instruction;
if (instruction.type == TurnType::Suppressed)
{
// count intersections. We cannot use exit, since intersections can follow directly
// after a roundabout
steps[last_valid_instruction] = elongate(steps[last_valid_instruction], step);
step.maneuver.instruction = TurnInstruction::NO_TURN();
}
else if (!isSilent(instruction))
{
// Remember the last non silent instruction
last_valid_instruction = step_index;
}
}
return removeNoTurnInstructions(std::move(steps));
}
} // namespace guidance } // namespace guidance
} // namespace engine } // namespace engine
} // namespace osrm } // namespace osrm
+29 -1
View File
@@ -184,6 +184,8 @@ Status TilePlugin::HandleRequest(const api::TileParameters &parameters, std::str
std::vector<int> used_weights; std::vector<int> used_weights;
std::unordered_map<int, std::size_t> weight_offsets; std::unordered_map<int, std::size_t> weight_offsets;
uint8_t max_datasource_id = 0; uint8_t max_datasource_id = 0;
std::vector<std::string> names;
std::unordered_map<std::string, std::size_t> name_offsets;
// Loop over all edges once to tally up all the attributes we'll need. // Loop over all edges once to tally up all the attributes we'll need.
// We need to do this so that we know the attribute offsets to use // We need to do this so that we know the attribute offsets to use
@@ -237,6 +239,14 @@ Status TilePlugin::HandleRequest(const api::TileParameters &parameters, std::str
// data to the layer attribute values // data to the layer attribute values
max_datasource_id = std::max(max_datasource_id, forward_datasource); max_datasource_id = std::max(max_datasource_id, forward_datasource);
max_datasource_id = std::max(max_datasource_id, reverse_datasource); max_datasource_id = std::max(max_datasource_id, reverse_datasource);
std::string name = facade.GetNameForID(edge.name_id);
if (name_offsets.find(name) == name_offsets.end())
{
names.push_back(name);
name_offsets[name] = names.size() - 1;
}
} }
// TODO: extract speed values for compressed and uncompressed geometries // TODO: extract speed values for compressed and uncompressed geometries
@@ -279,6 +289,8 @@ Status TilePlugin::HandleRequest(const api::TileParameters &parameters, std::str
uint8_t forward_datasource = 0; uint8_t forward_datasource = 0;
uint8_t reverse_datasource = 0; uint8_t reverse_datasource = 0;
std::string name = facade.GetNameForID(edge.name_id);
if (edge.forward_packed_geometry_id != SPECIAL_EDGEID) if (edge.forward_packed_geometry_id != SPECIAL_EDGEID)
{ {
std::vector<EdgeWeight> forward_weight_vector; std::vector<EdgeWeight> forward_weight_vector;
@@ -316,11 +328,12 @@ Status TilePlugin::HandleRequest(const api::TileParameters &parameters, std::str
max_datasource_id = std::max(max_datasource_id, forward_datasource); max_datasource_id = std::max(max_datasource_id, forward_datasource);
max_datasource_id = std::max(max_datasource_id, reverse_datasource); max_datasource_id = std::max(max_datasource_id, reverse_datasource);
const auto encode_tile_line = [&layer_writer, &edge, &id, &max_datasource_id]( const auto encode_tile_line = [&layer_writer, &edge, &id, &max_datasource_id, &used_weights](
const detail::FixedLine &tile_line, const detail::FixedLine &tile_line,
const std::uint32_t speed_kmh, const std::uint32_t speed_kmh,
const std::size_t duration, const std::size_t duration,
const std::uint8_t datasource, const std::uint8_t datasource,
const std::size_t name,
std::int32_t &start_x, std::int32_t &start_x,
std::int32_t &start_y) { std::int32_t &start_y) {
// Here, we save the two attributes for our feature: the speed and the // Here, we save the two attributes for our feature: the speed and the
@@ -356,6 +369,10 @@ Status TilePlugin::HandleRequest(const api::TileParameters &parameters, std::str
field.add_element(3); // "duration" tag key offset field.add_element(3); // "duration" tag key offset
field.add_element(130 + max_datasource_id + 1 + field.add_element(130 + max_datasource_id + 1 +
duration); // duration value offset duration); // duration value offset
field.add_element(4); // "name" tag key offset
field.add_element(130 + max_datasource_id + 1 +
used_weights.size() + name); // name value offset
} }
{ {
@@ -383,6 +400,7 @@ Status TilePlugin::HandleRequest(const api::TileParameters &parameters, std::str
speed_kmh, speed_kmh,
weight_offsets[forward_weight], weight_offsets[forward_weight],
forward_datasource, forward_datasource,
name_offsets[name],
start_x, start_x,
start_y); start_y);
} }
@@ -406,6 +424,7 @@ Status TilePlugin::HandleRequest(const api::TileParameters &parameters, std::str
speed_kmh, speed_kmh,
weight_offsets[reverse_weight], weight_offsets[reverse_weight],
reverse_datasource, reverse_datasource,
name_offsets[name],
start_x, start_x,
start_y); start_y);
} }
@@ -420,6 +439,7 @@ Status TilePlugin::HandleRequest(const api::TileParameters &parameters, std::str
layer_writer.add_string(util::vector_tile::KEY_TAG, "is_small"); layer_writer.add_string(util::vector_tile::KEY_TAG, "is_small");
layer_writer.add_string(util::vector_tile::KEY_TAG, "datasource"); layer_writer.add_string(util::vector_tile::KEY_TAG, "datasource");
layer_writer.add_string(util::vector_tile::KEY_TAG, "duration"); layer_writer.add_string(util::vector_tile::KEY_TAG, "duration");
layer_writer.add_string(util::vector_tile::KEY_TAG, "name");
// Now, we write out the possible speed value arrays and possible is_tiny // Now, we write out the possible speed value arrays and possible is_tiny
// values. Field type 4 is the "values" field. It's a variable type field, // values. Field type 4 is the "values" field. It's a variable type field,
@@ -458,6 +478,14 @@ Status TilePlugin::HandleRequest(const api::TileParameters &parameters, std::str
// to seconds with a simple /10 for display // to seconds with a simple /10 for display
values_writer.add_double(util::vector_tile::VARIANT_TYPE_DOUBLE, weight / 10.); values_writer.add_double(util::vector_tile::VARIANT_TYPE_DOUBLE, weight / 10.);
} }
for (const auto& name : names)
{
// Writing field type 4 == variant type
protozero::pbf_writer values_writer(layer_writer, util::vector_tile::VARIANT_TAG);
// Attribute value 1 == string type
values_writer.add_string(util::vector_tile::VARIANT_TYPE_STRING, name);
}
} }
return Status::Ok; return Status::Ok;
+3 -1
View File
@@ -47,7 +47,9 @@ ExtractionContainers::ExtractionContainers()
{ {
// Check if stxxl can be instantiated // Check if stxxl can be instantiated
stxxl::vector<unsigned> dummy_vector; stxxl::vector<unsigned> dummy_vector;
// Insert the empty string, it has no data and is zero length // Insert three empty strings for name, destination and pronunciation
name_lengths.push_back(0);
name_lengths.push_back(0);
name_lengths.push_back(0); name_lengths.push_back(0);
} }
+4
View File
@@ -27,6 +27,7 @@ namespace extractor
ExtractorCallbacks::ExtractorCallbacks(ExtractionContainers &extraction_containers) ExtractorCallbacks::ExtractorCallbacks(ExtractionContainers &extraction_containers)
: external_memory(extraction_containers) : external_memory(extraction_containers)
{ {
// we reserved 0, 1, 2 for the empty case
string_map[MapKey("", "")] = 0; string_map[MapKey("", "")] = 0;
} }
@@ -192,6 +193,9 @@ void ExtractorCallbacks::ProcessWay(const osmium::Way &input_way, const Extracti
((parsed_way.forward_speed != parsed_way.backward_speed) || ((parsed_way.forward_speed != parsed_way.backward_speed) ||
(parsed_way.forward_travel_mode != parsed_way.backward_travel_mode)); (parsed_way.forward_travel_mode != parsed_way.backward_travel_mode));
external_memory.used_node_id_list.reserve(external_memory.used_node_id_list.size() +
input_way.nodes().size());
std::transform(input_way.nodes().begin(), std::transform(input_way.nodes().begin(),
input_way.nodes().end(), input_way.nodes().end(),
std::back_inserter(external_memory.used_node_id_list), std::back_inserter(external_memory.used_node_id_list),
@@ -240,14 +240,16 @@ Intersection IntersectionGenerator::mergeSegregatedRoads(Intersection intersecti
if (is_connected_to_roundabout) if (is_connected_to_roundabout)
{ {
// We are merging a u-turn against the direction of a roundabout /*
// * We are merging a u-turn against the direction of a roundabout
// -----------> roundabout *
// / \ * -----------> roundabout
// out in * / \
// * out in
// These cases have to be disabled, even if they are not forbidden specifically by a *
// relation * These cases have to be disabled, even if they are not forbidden specifically by a
* relation
*/
intersection[0].entry_allowed = false; intersection[0].entry_allowed = false;
} }
+4 -4
View File
@@ -385,7 +385,7 @@ Intersection MotorwayHandler::fromRamp(const EdgeID via_eid, Intersection inters
{ {
// circular order indicates a merge to the left (0-3 onto 4 // circular order indicates a merge to the left (0-3 onto 4
if (angularDeviation(intersection[1].turn.angle, STRAIGHT_ANGLE) < if (angularDeviation(intersection[1].turn.angle, STRAIGHT_ANGLE) <
NARROW_TURN_ANGLE) 2*NARROW_TURN_ANGLE)
intersection[1].turn.instruction = {TurnType::Merge, intersection[1].turn.instruction = {TurnType::Merge,
DirectionModifier::SlightLeft}; DirectionModifier::SlightLeft};
else // fallback else // fallback
@@ -407,12 +407,12 @@ Intersection MotorwayHandler::fromRamp(const EdgeID via_eid, Intersection inters
if (detail::isMotorwayClass(intersection[2].turn.eid, node_based_graph) && if (detail::isMotorwayClass(intersection[2].turn.eid, node_based_graph) &&
node_based_graph.GetEdgeData(intersection[1].turn.eid).name_id != node_based_graph.GetEdgeData(intersection[1].turn.eid).name_id !=
EMPTY_NAMEID && EMPTY_NAMEID &&
node_based_graph.GetEdgeData(intersection[1].turn.eid).name_id == node_based_graph.GetEdgeData(intersection[2].turn.eid).name_id ==
node_based_graph.GetEdgeData(intersection[0].turn.eid).name_id) node_based_graph.GetEdgeData(intersection[1].turn.eid).name_id)
{ {
// circular order (5-0) onto 4 // circular order (5-0) onto 4
if (angularDeviation(intersection[2].turn.angle, STRAIGHT_ANGLE) < if (angularDeviation(intersection[2].turn.angle, STRAIGHT_ANGLE) <
NARROW_TURN_ANGLE) 2 * NARROW_TURN_ANGLE)
intersection[2].turn.instruction = {TurnType::Merge, intersection[2].turn.instruction = {TurnType::Merge,
DirectionModifier::SlightRight}; DirectionModifier::SlightRight};
else // fallback else // fallback
+22 -13
View File
@@ -1,5 +1,5 @@
#include "extractor/guidance/roundabout_handler.hpp"
#include "extractor/guidance/constants.hpp" #include "extractor/guidance/constants.hpp"
#include "extractor/guidance/roundabout_handler.hpp"
#include "extractor/guidance/toolkit.hpp" #include "extractor/guidance/toolkit.hpp"
#include "util/coordinate_calculation.hpp" #include "util/coordinate_calculation.hpp"
@@ -210,11 +210,11 @@ RoundaboutType RoundaboutHandler::getRoundaboutType(const NodeID nid) const
return util::Coordinate(node_info_list[node].lon, node_info_list[node].lat); return util::Coordinate(node_info_list[node].lon, node_info_list[node].lat);
}; };
unsigned roundabout_name_id = 0; std::unordered_set<unsigned> roundabout_name_ids;
std::unordered_set<unsigned> connected_names; std::unordered_set<unsigned> connected_names;
const auto getNextOnRoundabout = const auto getNextOnRoundabout =
[this, &roundabout_name_id, &connected_names](const NodeID node) { [this, &roundabout_name_ids, &connected_names](const NodeID node) {
EdgeID continue_edge = SPECIAL_EDGEID; EdgeID continue_edge = SPECIAL_EDGEID;
for (const auto edge : node_based_graph.GetAdjacentEdgeRange(node)) for (const auto edge : node_based_graph.GetAdjacentEdgeRange(node))
{ {
@@ -226,16 +226,24 @@ RoundaboutType RoundaboutHandler::getRoundaboutType(const NodeID nid) const
// fork in roundabout // fork in roundabout
return SPECIAL_EDGEID; return SPECIAL_EDGEID;
} }
// roundabout does not keep its name
if (roundabout_name_id != 0 && roundabout_name_id != edge_data.name_id &&
requiresNameAnnounced(name_table.GetNameForID(roundabout_name_id),
name_table.GetNameForID(edge_data.name_id),
street_name_suffix_table))
{
return SPECIAL_EDGEID;
}
roundabout_name_id = edge_data.name_id; if (EMPTY_NAMEID != edge_data.name_id)
{
bool add = true;
for (auto name_id : roundabout_name_ids)
{
if (!requiresNameAnnounced(name_table.GetNameForID(name_id),
name_table.GetNameForID(edge_data.name_id),
street_name_suffix_table))
{
add = false;
break;
}
}
if (add)
roundabout_name_ids.insert(edge_data.name_id);
}
continue_edge = edge; continue_edge = edge;
} }
@@ -320,7 +328,8 @@ RoundaboutType RoundaboutHandler::getRoundaboutType(const NodeID nid) const
// used with a reference and without. This will be fixed automatically // used with a reference and without. This will be fixed automatically
// when we handle references separately or if the useage is more consistent // when we handle references separately or if the useage is more consistent
if (0 != roundabout_name_id && 0 == connected_names.count(roundabout_name_id)) if (1 == roundabout_name_ids.size() &&
0 == connected_names.count(*roundabout_name_ids.begin()))
return RoundaboutType::Rotary; return RoundaboutType::Rotary;
else else
return RoundaboutType::Roundabout; return RoundaboutType::Roundabout;
+35 -8
View File
@@ -1,5 +1,5 @@
#include "extractor/guidance/turn_analysis.hpp"
#include "extractor/guidance/constants.hpp" #include "extractor/guidance/constants.hpp"
#include "extractor/guidance/turn_analysis.hpp"
#include "util/coordinate.hpp" #include "util/coordinate.hpp"
#include "util/coordinate_calculation.hpp" #include "util/coordinate_calculation.hpp"
@@ -127,15 +127,15 @@ Intersection TurnAnalysis::handleSliproads(const EdgeID source_edge_id,
auto intersection_node_id = node_based_graph.GetTarget(source_edge_id); auto intersection_node_id = node_based_graph.GetTarget(source_edge_id);
const auto linkTest = [this](const ConnectedRoad &road) { const auto linkTest = [this](const ConnectedRoad &road) {
return isLinkClass( return // isLinkClass(
node_based_graph.GetEdgeData(road.turn.eid).road_classification.road_class) && // node_based_graph.GetEdgeData(road.turn.eid).road_classification.road_class) &&
road.entry_allowed && !node_based_graph.GetEdgeData(road.turn.eid).roundabout && road.entry_allowed &&
angularDeviation(road.turn.angle, STRAIGHT_ANGLE) < NARROW_TURN_ANGLE; angularDeviation(road.turn.angle, STRAIGHT_ANGLE) <= 2 * NARROW_TURN_ANGLE;
}; };
bool hasRamp = bool hasNarrow =
std::find_if(intersection.begin(), intersection.end(), linkTest) != intersection.end(); std::find_if(intersection.begin(), intersection.end(), linkTest) != intersection.end();
if (!hasRamp) if (!hasNarrow)
return intersection; return intersection;
const auto source_edge_data = node_based_graph.GetEdgeData(source_edge_id); const auto source_edge_data = node_based_graph.GetEdgeData(source_edge_id);
@@ -171,6 +171,8 @@ Intersection TurnAnalysis::handleSliproads(const EdgeID source_edge_id,
const auto next_road_next_intersection = const auto next_road_next_intersection =
intersection_generator(intersection_node_id, next_road->turn.eid); intersection_generator(intersection_node_id, next_road->turn.eid);
const auto next_intersection_node = node_based_graph.GetTarget(next_road->turn.eid);
std::unordered_set<NameID> target_road_names; std::unordered_set<NameID> target_road_names;
for (const auto &road : next_road_next_intersection) for (const auto &road : next_road_next_intersection)
@@ -187,7 +189,8 @@ Intersection TurnAnalysis::handleSliproads(const EdgeID source_edge_id,
for (const auto &candidate_road : target_intersection) for (const auto &candidate_road : target_intersection)
{ {
const auto &candidate_data = node_based_graph.GetEdgeData(candidate_road.turn.eid); const auto &candidate_data = node_based_graph.GetEdgeData(candidate_road.turn.eid);
if (target_road_names.count(candidate_data.name_id) > 0) if (target_road_names.count(candidate_data.name_id) > 0 &&
node_based_graph.GetTarget(candidate_road.turn.eid) == next_intersection_node)
{ {
road.turn.instruction.type = TurnType::Sliproad; road.turn.instruction.type = TurnType::Sliproad;
break; break;
@@ -196,6 +199,30 @@ Intersection TurnAnalysis::handleSliproads(const EdgeID source_edge_id,
} }
} }
if (next_road->turn.instruction.type == TurnType::Fork)
{
const auto &next_data = node_based_graph.GetEdgeData(next_road->turn.eid);
if (next_data.name_id == source_edge_data.name_id)
{
if (angularDeviation(next_road->turn.angle, STRAIGHT_ANGLE) < 5)
next_road->turn.instruction.type = TurnType::Suppressed;
else
next_road->turn.instruction.type = TurnType::Continue;
next_road->turn.instruction.direction_modifier =
getTurnDirection(next_road->turn.angle);
}
else if (next_data.name_id != EMPTY_NAMEID)
{
next_road->turn.instruction.type = TurnType::NewName;
next_road->turn.instruction.direction_modifier =
getTurnDirection(next_road->turn.angle);
}
else
{
next_road->turn.instruction.type = TurnType::Suppressed;
}
}
return intersection; return intersection;
} }
+49 -16
View File
@@ -1,7 +1,7 @@
#include "extractor/guidance/turn_handler.hpp"
#include "extractor/guidance/constants.hpp" #include "extractor/guidance/constants.hpp"
#include "extractor/guidance/intersection_scenario_three_way.hpp" #include "extractor/guidance/intersection_scenario_three_way.hpp"
#include "extractor/guidance/toolkit.hpp" #include "extractor/guidance/toolkit.hpp"
#include "extractor/guidance/turn_handler.hpp"
#include "util/guidance/toolkit.hpp" #include "util/guidance/toolkit.hpp"
@@ -69,9 +69,6 @@ Intersection TurnHandler::handleTwoWayTurn(const EdgeID via_edge, Intersection i
intersection[1].turn.instruction = intersection[1].turn.instruction =
getInstructionForObvious(intersection.size(), via_edge, false, intersection[1]); getInstructionForObvious(intersection.size(), via_edge, false, intersection[1]);
if (intersection[1].turn.instruction.type == TurnType::Suppressed)
intersection[1].turn.instruction.type = TurnType::NoTurn;
return intersection; return intersection;
} }
@@ -112,8 +109,12 @@ Intersection TurnHandler::handleThreeWayTurn(const EdgeID via_edge, Intersection
const bool is_much_narrower_than_other = const bool is_much_narrower_than_other =
angularDeviation(other.turn.angle, STRAIGHT_ANGLE) / angularDeviation(other.turn.angle, STRAIGHT_ANGLE) /
angularDeviation(road.turn.angle, STRAIGHT_ANGLE) > angularDeviation(road.turn.angle, STRAIGHT_ANGLE) >
INCREASES_BY_FOURTY_PERCENT; INCREASES_BY_FOURTY_PERCENT &&
angularDeviation(angularDeviation(other.turn.angle, STRAIGHT_ANGLE),
angularDeviation(road.turn.angle, STRAIGHT_ANGLE)) >
FUZZY_ANGLE_DIFFERENCE;
return is_much_narrower_than_other; return is_much_narrower_than_other;
}; };
@@ -132,13 +133,9 @@ Intersection TurnHandler::handleThreeWayTurn(const EdgeID via_edge, Intersection
.road_classification.road_class; .road_classification.road_class;
const auto right_class = node_based_graph.GetEdgeData(intersection[1].turn.eid) const auto right_class = node_based_graph.GetEdgeData(intersection[1].turn.eid)
.road_classification.road_class; .road_classification.road_class;
if (canBeSeenAsFork(left_class, right_class)) if (isObviousOfTwo(intersection[1], intersection[2]) &&
{ (second_data.name_id != in_data.name_id ||
assignFork(via_edge, intersection[2], intersection[1]); first_data.name_id == second_data.name_id))
}
else if (isObviousOfTwo(intersection[1], intersection[2]) &&
(second_data.name_id != in_data.name_id ||
first_data.name_id == second_data.name_id))
{ {
intersection[1].turn.instruction = intersection[1].turn.instruction =
getInstructionForObvious(intersection.size(), via_edge, false, intersection[1]); getInstructionForObvious(intersection.size(), via_edge, false, intersection[1]);
@@ -154,6 +151,10 @@ Intersection TurnHandler::handleThreeWayTurn(const EdgeID via_edge, Intersection
intersection[1].turn.instruction = {findBasicTurnType(via_edge, intersection[1]), intersection[1].turn.instruction = {findBasicTurnType(via_edge, intersection[1]),
DirectionModifier::SlightRight}; DirectionModifier::SlightRight};
} }
else if (canBeSeenAsFork(left_class, right_class))
{
assignFork(via_edge, intersection[2], intersection[1]);
}
else else
{ {
intersection[1].turn.instruction = {findBasicTurnType(via_edge, intersection[1]), intersection[1].turn.instruction = {findBasicTurnType(via_edge, intersection[1]),
@@ -380,8 +381,12 @@ std::size_t TurnHandler::findObviousTurn(const EdgeID via_edge,
} }
const auto out_data = node_based_graph.GetEdgeData(intersection[i].turn.eid); const auto out_data = node_based_graph.GetEdgeData(intersection[i].turn.eid);
auto continue_class = node_based_graph.GetEdgeData(intersection[best_continue].turn.eid)
.road_classification.road_class;
if (intersection[i].entry_allowed && out_data.name_id == in_data.name_id && if (intersection[i].entry_allowed && out_data.name_id == in_data.name_id &&
deviation < best_continue_deviation) (best_continue == 0 || continue_class > out_data.road_classification.road_class ||
(deviation < best_continue_deviation &&
out_data.road_classification.road_class == continue_class)))
{ {
best_continue_deviation = deviation; best_continue_deviation = deviation;
best_continue = i; best_continue = i;
@@ -395,7 +400,12 @@ std::size_t TurnHandler::findObviousTurn(const EdgeID via_edge,
return 0; return 0;
// has no obvious continued road // has no obvious continued road
if (best_continue == 0 || true) if (best_continue == 0 || best_continue_deviation >= 2 * NARROW_TURN_ANGLE ||
(node_based_graph.GetEdgeData(intersection[best_continue].turn.eid)
.road_classification.road_class ==
node_based_graph.GetEdgeData(intersection[best].turn.eid)
.road_classification.road_class &&
std::abs(best_continue_deviation) > 1 && best_deviation / best_continue_deviation < 0.75))
{ {
// Find left/right deviation // Find left/right deviation
const double left_deviation = angularDeviation( const double left_deviation = angularDeviation(
@@ -425,8 +435,31 @@ std::size_t TurnHandler::findObviousTurn(const EdgeID via_edge,
return best; return best;
} }
} }
else
{
const double deviation =
angularDeviation(intersection[best_continue].turn.angle, STRAIGHT_ANGLE);
const auto &continue_data =
node_based_graph.GetEdgeData(intersection[best_continue].turn.eid);
if (std::abs(deviation) < 1)
return best_continue;
return 0; // no obvious turn // check if any other similar best continues exist
for (std::size_t i = 1; i < intersection.size(); ++i)
{
if (i == best_continue || !intersection[i].entry_allowed)
continue;
if (angularDeviation(intersection[i].turn.angle, STRAIGHT_ANGLE) / deviation < 1.1 &&
continue_data.road_classification.road_class ==
node_based_graph.GetEdgeData(intersection[i].turn.eid)
.road_classification.road_class)
return 0;
}
return best_continue; // no obvious turn
}
return 0;
} }
// Assignment of left turns hands of to right turns. // Assignment of left turns hands of to right turns.
-1
View File
@@ -5,7 +5,6 @@
#include <boost/algorithm/string.hpp> #include <boost/algorithm/string.hpp>
#include <boost/assert.hpp> #include <boost/assert.hpp>
#include <boost/range/adaptor/transformed.hpp>
#include <boost/ref.hpp> #include <boost/ref.hpp>
#include <iterator> #include <iterator>
+2 -1
View File
@@ -105,9 +105,10 @@ void RequestHandler::HandleRequest(const http::request &current_request, http::r
else else
{ {
BOOST_ASSERT(result.is<std::string>()); BOOST_ASSERT(result.is<std::string>());
current_reply.content.resize(result.get<std::string>().size());
std::copy(result.get<std::string>().cbegin(), std::copy(result.get<std::string>().cbegin(),
result.get<std::string>().cend(), result.get<std::string>().cend(),
std::back_inserter(current_reply.content)); current_reply.content.begin());
current_reply.headers.emplace_back("Content-Type", "application/x-protobuf"); current_reply.headers.emplace_back("Content-Type", "application/x-protobuf");
} }
+3 -3
View File
@@ -247,8 +247,8 @@ int Storage::Run()
coordinate_list_size); coordinate_list_size);
// we'll read a list of OSM node IDs from the same data, so set the block size for the same // we'll read a list of OSM node IDs from the same data, so set the block size for the same
// number of items: // number of items:
shared_layout_ptr->SetBlockSize<OSMNodeID>(SharedDataLayout::OSM_NODE_ID_LIST, shared_layout_ptr->SetBlockSize<std::uint64_t>(SharedDataLayout::OSM_NODE_ID_LIST,
util::PackedVectorSize(coordinate_list_size)); util::PackedVector<OSMNodeID>::elements_to_blocks(coordinate_list_size));
// load geometries sizes // load geometries sizes
boost::filesystem::ifstream geometry_input_stream(config.geometries_path, std::ios::binary); boost::filesystem::ifstream geometry_input_stream(config.geometries_path, std::ios::binary);
@@ -540,7 +540,7 @@ int Storage::Run()
// Loading list of coordinates // Loading list of coordinates
util::Coordinate *coordinates_ptr = shared_layout_ptr->GetBlockPtr<util::Coordinate, true>( util::Coordinate *coordinates_ptr = shared_layout_ptr->GetBlockPtr<util::Coordinate, true>(
shared_memory_ptr, SharedDataLayout::COORDINATE_LIST); shared_memory_ptr, SharedDataLayout::COORDINATE_LIST);
OSMNodeID *osmnodeid_ptr = shared_layout_ptr->GetBlockPtr<OSMNodeID, true>( std::uint64_t *osmnodeid_ptr = shared_layout_ptr->GetBlockPtr<std::uint64_t, true>(
shared_memory_ptr, SharedDataLayout::OSM_NODE_ID_LIST); shared_memory_ptr, SharedDataLayout::OSM_NODE_ID_LIST);
util::PackedVector<OSMNodeID, true> osmnodeid_list; util::PackedVector<OSMNodeID, true> osmnodeid_list;
osmnodeid_list.reset( osmnodeid_list.reset(
+5 -2
View File
@@ -54,7 +54,7 @@ BOOST_AUTO_TEST_CASE(test_tile)
BOOST_CHECK_EQUAL(feature_message.tag(), util::vector_tile::FEATURE_ATTRIBUTES_TAG); BOOST_CHECK_EQUAL(feature_message.tag(), util::vector_tile::FEATURE_ATTRIBUTES_TAG);
// properties // properties
std::tie(value_begin, value_end) = feature_message.get_packed_uint32(); std::tie(value_begin, value_end) = feature_message.get_packed_uint32();
BOOST_CHECK_EQUAL(std::distance(value_begin, value_end), 8); BOOST_CHECK_EQUAL(std::distance(value_begin, value_end), 10);
auto iter = value_begin; auto iter = value_begin;
BOOST_CHECK_EQUAL(*iter++, 0); // speed key BOOST_CHECK_EQUAL(*iter++, 0); // speed key
BOOST_CHECK_LT(*iter++, 128); // speed value BOOST_CHECK_LT(*iter++, 128); // speed value
@@ -67,6 +67,9 @@ BOOST_AUTO_TEST_CASE(test_tile)
*iter++; // skip value check, can be valud uint32 *iter++; // skip value check, can be valud uint32
BOOST_CHECK_EQUAL(*iter++, 3); // duration key BOOST_CHECK_EQUAL(*iter++, 3); // duration key
BOOST_CHECK_GT(*iter++, 130); // duration value BOOST_CHECK_GT(*iter++, 130); // duration value
// name
BOOST_CHECK_EQUAL(*iter++, 4);
BOOST_CHECK_GT(*iter++, 130);
BOOST_CHECK(iter == value_end); BOOST_CHECK(iter == value_end);
// geometry // geometry
feature_message.next(); feature_message.next();
@@ -128,7 +131,7 @@ BOOST_AUTO_TEST_CASE(test_tile)
} }
} }
BOOST_CHECK_EQUAL(number_of_keys, 4); BOOST_CHECK_EQUAL(number_of_keys, 5);
BOOST_CHECK_GT(number_of_values, 128); // speed value resolution BOOST_CHECK_GT(number_of_values, 128); // speed value resolution
} }