[osrm] 03/22: Imported Upstream version 5.0.0~rc2+ds
Sebastiaan Couwenberg
sebastic at moszumanska.debian.org
Fri Apr 29 22:44:13 UTC 2016
This is an automated email from the git hooks/post-receive script.
sebastic pushed a commit to branch master
in repository osrm.
commit 0f417a46547154585fb801e7c7e373fc7452001f
Author: Bas Couwenberg <sebastic at xs4all.nl>
Date: Fri Apr 29 23:13:13 2016 +0200
Imported Upstream version 5.0.0~rc2+ds
---
.gitignore | 1 +
.travis.yml | 83 +-
CHANGELOG.md | 25 +
CMakeLists.txt | 80 +-
README.md | 1 +
appveyor-build.bat | 6 +-
cmake/pkgconfig.in | 4 +-
cucumber.js | 4 +-
features/bicycle/access.feature | 5 +-
features/bicycle/access_node.feature | 5 +-
features/bicycle/destination.feature | 46 +-
features/bicycle/mode.feature | 84 +-
features/bicycle/pushing.feature | 22 +-
features/bicycle/roundabout.feature | 30 -
features/car/access.feature | 6 +-
features/car/destination.feature | 46 +-
features/car/mode.feature | 18 +-
features/car/roundabout.feature | 30 -
features/foot/access.feature | 4 +-
features/foot/access_node.feature | 4 +-
features/guidance/continue.feature | 90 +
features/guidance/end-of-road.feature | 106 +
features/guidance/fork.feature | 213 ++
features/guidance/merge.feature | 52 +
features/guidance/motorway.feature | 100 +-
features/guidance/new-name.feature | 135 ++
features/guidance/ramp.feature | 229 ++
features/guidance/rotary-bike.feature | 167 ++
features/guidance/rotary.feature | 262 +++
...{roundabout.feature => roundabout-bike.feature} | 87 +-
features/guidance/roundabout.feature | 182 +-
features/guidance/suppressed.feature | 66 +
features/guidance/turn.feature | 284 +++
features/step_definitions/requests.js | 9 +-
features/step_definitions/trip.js | 1 +
features/support/env.js | 3 +-
features/support/route.js | 7 +-
features/support/shared_steps.js | 10 +-
features/testbot/graph.feature | 4 +-
features/testbot/matching.feature | 19 +
features/testbot/overlap.feature | 20 +-
features/testbot/roundabout.feature | 76 -
features/testbot/status.feature | 38 +-
features/testbot/turn_angles.feature | 74 -
features/testbot/turns.feature | 115 -
features/testbot/uturn.feature | 93 -
include/contractor/graph_contractor.hpp | 6 +-
include/engine/api/json_factory.hpp | 3 +-
include/engine/api/match_api.hpp | 4 +-
include/engine/api/nearest_api.hpp | 2 +-
include/engine/api/route_api.hpp | 20 +-
include/engine/api/route_parameters.hpp | 12 +-
include/engine/api/table_api.hpp | 6 +-
include/engine/api/trip_api.hpp | 8 +-
include/engine/datafacade/datafacade_base.hpp | 2 +-
include/engine/datafacade/internal_datafacade.hpp | 2 +-
include/engine/datafacade/shared_datafacade.hpp | 3 +-
include/engine/douglas_peucker.hpp | 61 +-
include/engine/geospatial_query.hpp | 8 +-
include/engine/guidance/assemble_leg.hpp | 117 +-
include/engine/guidance/assemble_steps.hpp | 54 +-
include/engine/guidance/route_leg.hpp | 4 -
include/engine/guidance/route_step.hpp | 3 +-
include/engine/hint.hpp | 4 +-
.../engine/map_matching/hidden_markov_model.hpp | 4 +-
include/engine/phantom_node.hpp | 2 +-
include/engine/plugins/plugin_base.hpp | 7 +-
.../engine/routing_algorithms/alternative_path.hpp | 40 +-
include/engine/routing_algorithms/map_matching.hpp | 4 +-
.../engine/routing_algorithms/shortest_path.hpp | 10 +-
include/extractor/guidance/constants.hpp | 32 +
include/extractor/guidance/intersection.hpp | 66 +
.../extractor/guidance/intersection_generator.hpp | 68 +
.../extractor/guidance/intersection_handler.hpp | 71 +
include/extractor/guidance/motorway_handler.hpp | 51 +
include/extractor/guidance/roundabout_handler.hpp | 71 +
include/extractor/guidance/toolkit.hpp | 74 +-
include/extractor/guidance/turn_analysis.hpp | 175 +-
include/extractor/guidance/turn_handler.hpp | 74 +
include/extractor/guidance/turn_instruction.hpp | 20 +-
include/extractor/profile_properties.hpp | 4 +-
include/extractor/restriction_parser.hpp | 2 +-
include/server/api/base_parameters_grammar.hpp | 110 +-
include/server/api/match_parameter_grammar.hpp | 38 +-
include/server/api/nearest_parameter_grammar.hpp | 15 +-
include/server/api/parameters_parser.hpp | 2 +-
include/server/api/parsed_url.hpp | 18 +-
include/server/api/route_parameters_grammar.hpp | 48 +-
include/server/api/table_parameter_grammar.hpp | 28 +-
include/server/api/tile_parameter_grammar.hpp | 35 +-
include/server/api/trip_parameter_grammar.hpp | 33 +-
include/server/api/url_parser.hpp | 4 +-
include/storage/storage.hpp | 27 +
include/storage/storage_config.hpp | 27 +
include/util/coordinate_calculation.hpp | 48 +-
include/util/name_table.hpp | 2 +-
include/util/range_table.hpp | 7 +-
include/util/rectangle.hpp | 6 +-
include/util/static_rtree.hpp | 64 +-
include/util/viewport.hpp | 22 +-
include/util/web_mercator.hpp | 127 ++
profiles/bicycle.lua | 16 +-
profiles/car.lua | 13 +-
profiles/foot.lua | 16 +-
profiles/lib/access.lua | 4 +-
profiles/testbot.lua | 8 +-
scripts/poly2req.js | 132 ++
scripts/timer.sh | 12 +
src/benchmarks/CMakeLists.txt | 20 +
src/contractor/contractor.cpp | 2 +-
src/engine/api/json_factory.cpp | 38 +-
src/engine/douglas_peucker.cpp | 40 +-
src/engine/guidance/post_processing.cpp | 63 +-
src/engine/plugins/match.cpp | 6 +-
src/engine/plugins/tile.cpp | 24 +-
src/engine/plugins/trip.cpp | 2 +-
src/engine/plugins/viaroute.cpp | 16 +-
src/extractor/edge_based_graph_factory.cpp | 13 +-
src/extractor/extractor.cpp | 2 +-
src/extractor/extractor_callbacks.cpp | 1 +
src/extractor/guidance/intersection.cpp | 31 +
src/extractor/guidance/intersection_generator.cpp | 255 +++
src/extractor/guidance/intersection_handler.cpp | 307 +++
src/extractor/guidance/motorway_handler.cpp | 524 +++++
src/extractor/guidance/roundabout_handler.cpp | 257 +++
src/extractor/guidance/turn_analysis.cpp | 2281 +-------------------
src/extractor/guidance/turn_handler.cpp | 1171 ++++++++++
src/extractor/restriction_parser.cpp | 2 +-
src/extractor/scripting_environment.cpp | 2 +-
src/server/api/parameters_parser.cpp | 45 +-
src/server/api/url_parser.cpp | 120 +-
src/server/connection.cpp | 1 +
src/server/request_handler.cpp | 6 +-
src/storage/storage.cpp | 1 +
src/tools/contract.cpp | 3 +-
src/tools/extract.cpp | 3 +-
src/tools/routed.cpp | 3 +-
src/tools/store.cpp | 3 +-
src/util/coordinate_calculation.cpp | 239 +-
src/util/name_table.cpp | 25 +-
taginfo.json | 1 +
test/data/Makefile | 47 +-
test/data/data.md5sum | 1 +
unit_tests/CMakeLists.txt | 76 +
unit_tests/engine/base64.cpp | 2 -
unit_tests/engine/douglas_peucker.cpp | 80 +-
unit_tests/library/equal_json.hpp | 7 +-
unit_tests/library/match.cpp | 34 +-
unit_tests/library/nearest.cpp | 4 +-
unit_tests/library/route.cpp | 96 +-
unit_tests/mocks/mock_datafacade.hpp | 2 +-
unit_tests/server/parameters_parser.cpp | 74 +-
unit_tests/server/url_parser.cpp | 14 +-
unit_tests/util/coordinate_calculation.cpp | 246 ++-
unit_tests/util/rectangle.cpp | 64 +-
unit_tests/util/static_rtree.cpp | 40 +-
unit_tests/util/web_mercator.cpp | 74 +
157 files changed, 6933 insertions(+), 4337 deletions(-)
diff --git a/.gitignore b/.gitignore
index 83f572d..dd46b9f 100644
--- a/.gitignore
+++ b/.gitignore
@@ -80,6 +80,7 @@ stxxl.errlog
/test/profile.lua
/test/cache
/test/speeds.csv
+/test/data/monaco.*
node_modules
# Deprecated config file #
diff --git a/.travis.yml b/.travis.yml
index 553cf56..df8df0a 100644
--- a/.travis.yml
+++ b/.travis.yml
@@ -26,8 +26,8 @@ matrix:
addons: &gcc5
apt:
sources: ['ubuntu-toolchain-r-test']
- packages: ['g++-5', 'libbz2-dev', 'libstxxl-dev', 'libstxxl1', 'libxml2-dev', 'libzip-dev', 'lua5.1', 'liblua5.1-0-dev', 'libtbb-dev', 'libgdal-dev', 'libluabind-dev', 'libboost-all-dev']
- env: COMPILER='g++-5' BUILD_TYPE='Debug'
+ packages: ['g++-5', 'libbz2-dev', 'libstxxl-dev', 'libstxxl1', 'libxml2-dev', 'libzip-dev', 'lua5.1', 'liblua5.1-0-dev', 'libtbb-dev', 'libgdal-dev', 'libluabind-dev', 'libboost-all-dev', 'pip']
+ env: CCOMPILER='gcc-5' CXXCOMPILER='g++-5' BUILD_TYPE='Debug' COVERAGE=ON
- os: linux
compiler: gcc
@@ -35,20 +35,20 @@ matrix:
apt:
sources: ['ubuntu-toolchain-r-test']
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']
- env: COMPILER='g++-4.8' BUILD_TYPE='Debug'
+ env: CCOMPILER='gcc-4.8' CXXCOMPILER='g++-4.8' BUILD_TYPE='Debug'
- os: linux
compiler: clang
addons: &clang38
apt:
- sources: ['llvm-toolchain-precise', 'ubuntu-toolchain-r-test']
+ 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']
- env: COMPILER='clang++-3.8' BUILD_TYPE='Debug' RUN_CLANG_FORMAT=ON
+ env: CCOMPILER='clang-3.8' CXXCOMPILER='clang++-3.8' BUILD_TYPE='Debug' RUN_CLANG_FORMAT=ON
- os: osx
osx_image: xcode7.3
compiler: clang
- env: COMPILER='clang++' BUILD_TYPE='Debug'
+ env: CCOMPILER='clang' CXXCOMPILER='clang++' BUILD_TYPE='Debug'
# Release Builds
- os: linux
@@ -57,7 +57,7 @@ matrix:
apt:
sources: ['ubuntu-toolchain-r-test']
packages: ['g++-5', 'libbz2-dev', 'libstxxl-dev', 'libstxxl1', 'libxml2-dev', 'libzip-dev', 'lua5.1', 'liblua5.1-0-dev', 'libtbb-dev', 'libgdal-dev', 'libluabind-dev', 'libboost-all-dev']
- env: COMPILER='g++-5' BUILD_TYPE='Release'
+ env: CCOMPILER='gcc-5' CXXCOMPILER='g++-5' BUILD_TYPE='Release'
- os: linux
compiler: gcc
@@ -65,20 +65,20 @@ matrix:
apt:
sources: ['ubuntu-toolchain-r-test']
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']
- env: COMPILER='g++-4.8' BUILD_TYPE='Release'
+ env: CCOMPILER='gcc-4.8' CXXCOMPILER='g++-4.8' BUILD_TYPE='Release'
- os: linux
compiler: clang
addons: &clang38
apt:
- sources: ['llvm-toolchain-precise', 'ubuntu-toolchain-r-test']
+ 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']
- env: COMPILER='clang++-3.8' BUILD_TYPE='Release'
+ env: CCOMPILER='clang-3.8' CXXCOMPILER='clang++-3.8' BUILD_TYPE='Release'
- os: osx
osx_image: xcode7.3
compiler: clang
- env: COMPILER='clang++' BUILD_TYPE='Release'
+ env: CCOMPILER='clang' CXXCOMPILER='clang++' BUILD_TYPE='Release'
# Shared Library
- os: linux
@@ -87,39 +87,15 @@ matrix:
apt:
sources: ['ubuntu-toolchain-r-test']
packages: ['g++-5', 'libbz2-dev', 'libstxxl-dev', 'libstxxl1', 'libxml2-dev', 'libzip-dev', 'lua5.1', 'liblua5.1-0-dev', 'libtbb-dev', 'libgdal-dev', 'libluabind-dev', 'libboost-all-dev']
- env: COMPILER='g++-5' BUILD_TYPE='Release' BUILD_SHARED_LIBS=ON
+ env: CCOMPILER='gcc-5' CXXCOMPILER='g++-5' BUILD_TYPE='Release' BUILD_SHARED_LIBS=ON
- os: linux
compiler: clang
addons: &clang38
apt:
- sources: ['llvm-toolchain-precise', 'ubuntu-toolchain-r-test']
+ 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']
- env: COMPILER='clang++-3.8' BUILD_TYPE='Release' BUILD_SHARED_LIBS=ON
-
-
- # Disabled until tests all pass on OSX:
- #
- # 3/ OSX Clang Builds
- #- os: osx
- # osx_image: xcode6.4
- # compiler: clang
- # env: COMPILER='clang++' BUILD_TYPE='Debug'
-
- #- os: osx
- # osx_image: xcode6.4
- # compiler: clang
- # env: COMPILER='clang++' BUILD_TYPE='Release'
-
- #- os: osx
- # osx_image: xcode6.4
- # compiler: clang
- # env: COMPILER='clang++' BUILD_TYPE='Release' BUILD_SHARED_LIBS=ON
-
- #- os: osx
- # osx_image: xcode7
- # compiler: clang
- # env: COMPILER='clang++' BUILD_TYPE='Release' BUILD_SHARED_LIBS=ON
+ env: CCOMPILER='clang-3.8' CXXCOMPILER='clang++-3.8' BUILD_TYPE='Release' BUILD_SHARED_LIBS=ON
before_install:
- source ./scripts/install_node.sh 4
@@ -129,11 +105,14 @@ install:
- DEPS_DIR="${TRAVIS_BUILD_DIR}/deps"
- mkdir -p ${DEPS_DIR} && cd ${DEPS_DIR}
- |
+ if [[ -n "${COVERAGE}" ]]; then
+ pip install --user cpp-coveralls
+ fi
+ - |
if [[ "${TRAVIS_OS_NAME}" == "linux" ]]; then
- CMAKE_URL="http://www.cmake.org/files/v3.3/cmake-3.3.2-Linux-x86_64.tar.gz"
+ CMAKE_URL="http://www.cmake.org/files/v3.5/cmake-3.5.1-Linux-x86_64.tar.gz"
mkdir cmake && travis_retry wget --quiet -O - ${CMAKE_URL} | tar --strip-components=1 -xz -C cmake
export PATH=${DEPS_DIR}/cmake/bin:${PATH}
-
elif [[ "${TRAVIS_OS_NAME}" == "osx" ]]; then
# implicit deps, but seem to be installed by default with recent images: libxml2 GDAL boost
brew install cmake libzip libstxxl lua51 luabind tbb md5sha1sum
@@ -146,9 +125,9 @@ before_script:
./scripts/check_taginfo.py taginfo.json profiles/car.lua
fi
- mkdir build && pushd build
- - export CXX=${COMPILER}
+ - export CC=${CCOMPILER} CXX=${CXXCOMPILER}
- export OSRM_PORT=5000 OSRM_TIMEOUT=6000
- - cmake .. -DCMAKE_BUILD_TYPE=${BUILD_TYPE} -DBUILD_SHARED_LIBS=${BUILD_SHARED_LIBS:-OFF} -DBUILD_TOOLS=1 -DENABLE_CCACHE=0
+ - cmake .. -DCMAKE_BUILD_TYPE=${BUILD_TYPE} -DBUILD_SHARED_LIBS=${BUILD_SHARED_LIBS:-OFF} -DCOVERAGE=${COVERAGE:-OFF} -DBUILD_TOOLS=1 -DENABLE_CCACHE=0
script:
- make --jobs=2
@@ -159,19 +138,29 @@ script:
if [[ "${TRAVIS_OS_NAME}" == "linux" ]]; then
sudo ldconfig
fi
- - ./extractor-tests
- - ./engine-tests
- - ./util-tests
+ - echo "travis_fold:start:UNIT_TESTS"
+ - ./unit_tests/extractor-tests
+ - ./unit_tests/engine-tests
+ - ./unit_tests/util-tests
+ - ./unit_tests/server-tests
+ - echo "travis_fold:end:UNIT_TESTS"
- popd
+ - echo "travis_fold:start:CUCUMBER"
- npm test
- - make -C test/data
- - ./build/library-tests test/data/monaco.osrm
+ - echo "travis_fold:end:CUCUMBER"
+ - echo "travis_fold:start:BENCHMARK"
+ - make -C test/data benchmark
+ - echo "travis_fold:end:BENCHMARK"
+ - ./build/unit_tests/library-tests test/data/monaco.osrm
- mkdir example/build && pushd example/build
- cmake ..
- make
- ./osrm-example ../../test/data/monaco.osrm
- popd
+
+after_success:
- |
if [ -n "$RUN_CLANG_FORMAT" ]; then
./scripts/format.sh || true # we don't want to fail just yet
fi
+ - coveralls --build-root build --exclude unit_tests --exclude third_party --exclude node_modules --gcov-options '\-lp'
diff --git a/CHANGELOG.md b/CHANGELOG.md
index 168b5ad..4430ff0 100644
--- a/CHANGELOG.md
+++ b/CHANGELOG.md
@@ -1,3 +1,28 @@
+# 5.0.0 RC2
+ - Profiles:
+ - `properties.allow_uturns_at_via` -> `properties.continue_straight_at_waypoint` (value is inverted!)
+ - API:
+ - Removed summary from legs property
+ - Disable steps and alternatives by default
+ - Fix `code` field: 'ok' -> 'Ok'
+ - Allow 4.json and 4.3.json format
+ - Conform to v5 spec and support "unlimited" as radiuses value.
+ - `uturns` parameter was replaced by `continue_straight` (value is inverted!)
+ - Features:
+ - Report progress for gennerating edge expanded edges in the edge based graph factory
+ - Add maxspeed=none tag to car profile.
+ - Optimize StaticRTree code: speedup 2x (to RC1)
+ - Optimize DouglasPeucker code: speedup 10x (to RC1)
+ - Optimize WebMercator projection: speedup 2x (to RC1)
+ - Bugs:
+ - #2195: Resolves issues with multiple includedirs in pkg-config file
+ - #2219: Internal server error when using the match plugin
+ - #2027: basename -> filename
+ - #2168: Report correct position where parsing failed
+ - #2036: Add license to storage and storage config exposed in public API
+ - Fix uturn detection in match plugin
+ - Add missing -lz to fix linking of server-tests
+
# 5.0.0 RC1
- Renamed osrm-prepare into osrm-contract
- osrm-contract does not need a profile parameter anymore
diff --git a/CMakeLists.txt b/CMakeLists.txt
index 3ca9c8a..dd3d188 100644
--- a/CMakeLists.txt
+++ b/CMakeLists.txt
@@ -32,8 +32,10 @@ endif()
option(ENABLE_CCACHE "Speed up incremental rebuilds via ccache" ON)
option(ENABLE_JSON_LOGGING "Adds additional JSON debug logging to the response" OFF)
option(BUILD_TOOLS "Build OSRM tools" OFF)
-option(BUILD_COMPONENTS "Build OSRM tools" ON)
+option(BUILD_COMPONENTS "Build osrm-components" ON)
option(ENABLE_ASSERTIONS OFF)
+option(COVERAGE OFF)
+option(SANITIZER OFF)
include_directories(BEFORE ${CMAKE_CURRENT_BINARY_DIR}/include/)
include_directories(BEFORE ${CMAKE_CURRENT_SOURCE_DIR}/include/)
@@ -46,10 +48,7 @@ add_custom_target(FingerPrintConfigure ALL ${CMAKE_COMMAND}
COMMENT "Configuring revision fingerprint"
VERBATIM)
-add_custom_target(tests DEPENDS engine-tests extractor-tests util-tests server-tests library-tests)
-add_custom_target(benchmarks DEPENDS rtree-bench)
-
-set(BOOST_COMPONENTS date_time filesystem iostreams program_options regex system thread unit_test_framework)
+set(BOOST_COMPONENTS date_time filesystem iostreams program_options regex system thread)
configure_file(
${CMAKE_CURRENT_SOURCE_DIR}/include/util/version.hpp.in
@@ -61,12 +60,6 @@ file(GLOB ContractorGlob src/contractor/*.cpp)
file(GLOB StorageGlob src/storage/*.cpp)
file(GLOB ServerGlob src/server/*.cpp src/server/**/*.cpp)
file(GLOB EngineGlob src/engine/*.cpp src/engine/**/*.cpp)
-file(GLOB ExtractorTestsGlob unit_tests/extractor/*.cpp)
-file(GLOB EngineTestsGlob unit_tests/engine/*.cpp)
-file(GLOB UtilTestsGlob unit_tests/util/*.cpp)
-file(GLOB ServerTestsGlob unit_tests/server/*.cpp)
-file(GLOB LibraryTestsGlob unit_tests/library/*.cpp)
-file(GLOB IOTestsGlob unit_tests/io/*.cpp)
add_library(UTIL OBJECT ${UtilGlob})
add_library(EXTRACTOR OBJECT ${ExtractorGlob})
@@ -87,21 +80,6 @@ add_library(osrm_extract $<TARGET_OBJECTS:EXTRACTOR> $<TARGET_OBJECTS:UTIL>)
add_library(osrm_contract $<TARGET_OBJECTS:CONTRACTOR> $<TARGET_OBJECTS:UTIL>)
add_library(osrm_store $<TARGET_OBJECTS:STORAGE> $<TARGET_OBJECTS:UTIL>)
-# Unit tests
-add_executable(engine-tests EXCLUDE_FROM_ALL unit_tests/engine_tests.cpp ${EngineTestsGlob} $<TARGET_OBJECTS:ENGINE> $<TARGET_OBJECTS:STORAGE> $<TARGET_OBJECTS:UTIL>)
-add_executable(extractor-tests EXCLUDE_FROM_ALL unit_tests/extractor_tests.cpp ${ExtractorTestsGlob} $<TARGET_OBJECTS:EXTRACTOR> $<TARGET_OBJECTS:UTIL>)
-add_executable(util-tests EXCLUDE_FROM_ALL unit_tests/util_tests.cpp ${UtilTestsGlob} $<TARGET_OBJECTS:UTIL>)
-add_executable(server-tests EXCLUDE_FROM_ALL unit_tests/server_tests.cpp ${ServerTestsGlob} $<TARGET_OBJECTS:UTIL> $<TARGET_OBJECTS:SERVER>)
-add_executable(library-tests EXCLUDE_FROM_ALL unit_tests/library_tests.cpp ${LibraryTestsGlob})
-
-# Benchmarks
-add_executable(rtree-bench EXCLUDE_FROM_ALL src/benchmarks/static_rtree.cpp $<TARGET_OBJECTS:UTIL>)
-
-target_include_directories(engine-tests PUBLIC ${CMAKE_CURRENT_SOURCE_DIR}/unit_tests)
-target_include_directories(util-tests PUBLIC ${CMAKE_CURRENT_SOURCE_DIR}/unit_tests)
-target_include_directories(library-tests PUBLIC ${CMAKE_CURRENT_SOURCE_DIR}/include ${CMAKE_CURRENT_SOURCE_DIR}/)
-target_include_directories(rtree-bench PUBLIC ${CMAKE_CURRENT_SOURCE_DIR}/unit_tests)
-
# Check the release mode
if(NOT CMAKE_BUILD_TYPE MATCHES Debug)
set(CMAKE_BUILD_TYPE Release)
@@ -157,8 +135,19 @@ if(CMAKE_BUILD_TYPE MATCHES Release)
endif()
endif()
-if(NOT WIN32)
- add_definitions(-DBOOST_TEST_DYN_LINK)
+set(MAYBE_COVERAGE_LIBRARIES "")
+if (COVERAGE)
+ if (NOT CMAKE_BUILD_TYPE MATCHES "Debug")
+ message(ERROR "COVERAGE=ON only make sense with a Debug build")
+ endif()
+ set(MAYBE_COVERAGE_LIBRARIES "gcov")
+ set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -ftest-coverage -fprofile-arcs")
+endif()
+if (SANITIZER)
+ if (NOT CMAKE_BUILD_TYPE MATCHES "Debug")
+ message(ERROR "SANITIZER=ON only make sense with a Debug build")
+ endif()
+ set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -fsanitize=address")
endif()
# Configuring compilers
@@ -242,11 +231,13 @@ find_package(Osmium REQUIRED COMPONENTS io)
include_directories(SYSTEM ${OSMIUM_INCLUDE_DIRS})
-find_package(Boost 1.49.0 COMPONENTS ${BOOST_COMPONENTS} REQUIRED)
+find_package(Boost 1.49.0 REQUIRED COMPONENTS ${BOOST_COMPONENTS})
if(NOT WIN32)
add_definitions(-DBOOST_TEST_DYN_LINK)
endif()
-add_definitions(-DBOOST_SPIRIT_USE_PHOENIX_V3 -DBOOST_RESULT_OF_USE_DECLTYPE)
+add_definitions(-DBOOST_SPIRIT_USE_PHOENIX_V3)
+add_definitions(-DBOOST_RESULT_OF_USE_DECLTYPE)
+add_definitions(-DBOOST_FILESYSTEM_NO_DEPRECATED)
include_directories(SYSTEM ${Boost_INCLUDE_DIRS})
find_package(Threads REQUIRED)
@@ -257,7 +248,7 @@ if(WIN32 AND CMAKE_BUILD_TYPE MATCHES Debug)
set(TBB_LIBRARIES ${TBB_DEBUG_LIBRARIES})
endif()
-find_package( Luabind REQUIRED )
+find_package(Luabind REQUIRED)
include(check_luabind)
include_directories(SYSTEM ${LUABIND_INCLUDE_DIR})
@@ -307,7 +298,8 @@ set(EXTRACTOR_LIBRARIES
${OSMIUM_LIBRARIES}
${STXXL_LIBRARY}
${TBB_LIBRARIES}
- ${ZLIB_LIBRARY})
+ ${ZLIB_LIBRARY}
+ ${MAYBE_COVERAGE_LIBRARIES})
set(CONTRACTOR_LIBRARIES
${Boost_LIBRARIES}
${CMAKE_THREAD_LIBS_INIT}
@@ -315,35 +307,32 @@ set(CONTRACTOR_LIBRARIES
${USED_LUA_LIBRARIES}
${STXXL_LIBRARY}
${TBB_LIBRARIES}
- ${MAYBE_RT_LIBRARY})
+ ${MAYBE_RT_LIBRARY}
+ ${MAYBE_COVERAGE_LIBRARIES})
set(ENGINE_LIBRARIES
${Boost_LIBRARIES}
${CMAKE_THREAD_LIBS_INIT}
${STXXL_LIBRARY}
${TBB_LIBRARIES}
- ${MAYBE_RT_LIBRARY})
+ ${MAYBE_RT_LIBRARY}
+ ${MAYBE_COVERAGE_LIBRARIES})
set(STORAGE_LIBRARIES
${Boost_LIBRARIES}
${CMAKE_THREAD_LIBS_INIT}
${TBB_LIBRARIES}
- ${MAYBE_RT_LIBRARY})
+ ${MAYBE_RT_LIBRARY}
+ ${MAYBE_COVERAGE_LIBRARIES})
set(UTIL_LIBRARIES
${Boost_LIBRARIES}
${CMAKE_THREAD_LIBS_INIT}
${STXXL_LIBRARY}
- ${TBB_LIBRARIES})
+ ${TBB_LIBRARIES}
+ ${MAYBE_COVERAGE_LIBRARIES})
# Libraries
target_link_libraries(osrm ${ENGINE_LIBRARIES})
target_link_libraries(osrm_contract ${CONTRACTOR_LIBRARIES})
target_link_libraries(osrm_extract ${EXTRACTOR_LIBRARIES})
target_link_libraries(osrm_store ${STORAGE_LIBRARIES})
-# Tests
-target_link_libraries(engine-tests ${ENGINE_LIBRARIES})
-target_link_libraries(server-tests osrm ${Boost_LIBRARIES})
-target_link_libraries(extractor-tests ${EXTRACTOR_LIBRARIES})
-target_link_libraries(rtree-bench ${Boost_LIBRARIES} ${CMAKE_THREAD_LIBS_INIT} ${TBB_LIBRARIES})
-target_link_libraries(util-tests ${UTIL_LIBRARIES})
-target_link_libraries(library-tests osrm ${Boost_LIBRARIES})
if(BUILD_COMPONENTS)
find_package(GDAL)
@@ -460,3 +449,8 @@ configure_file(
add_custom_target(uninstall
COMMAND ${CMAKE_COMMAND} -P ${CMAKE_CURRENT_BINARY_DIR}/cmake/cmake_uninstall.cmake)
+
+
+# Modular build system: each directory registered here provides its own CMakeLists.txt
+add_subdirectory(unit_tests)
+add_subdirectory(src/benchmarks)
diff --git a/README.md b/README.md
index d319d26..084cfba 100644
--- a/README.md
+++ b/README.md
@@ -10,6 +10,7 @@ The Open Source Routing Machine is a high performance routing engine written in
| Linux | develop | [![Build Status](https://travis-ci.org/Project-OSRM/osrm-backend.png?branch=develop)](https://travis-ci.org/Project-OSRM/osrm-backend) |
| Windows | master/develop | [![Build status](https://ci.appveyor.com/api/projects/status/4iuo3s9gxprmcjjh)](https://ci.appveyor.com/project/DennisOSRM/osrm-backend) |
| LUAbind fork | master | [![Build Status](https://travis-ci.org/DennisOSRM/luabind.png?branch=master)](https://travis-ci.org/DennisOSRM/luabind) |
+| Coverage | develop | [![Coverage Status](https://coveralls.io/repos/github/Project-OSRM/osrm-backend/badge.svg?branch=develop)](https://coveralls.io/github/Project-OSRM/osrm-backend?branch=develop) |
## Building
diff --git a/appveyor-build.bat b/appveyor-build.bat
index 568998b..5dbdfa2 100644
--- a/appveyor-build.bat
+++ b/appveyor-build.bat
@@ -117,13 +117,13 @@ IF %ERRORLEVEL% NEQ 0 GOTO ERROR
SET PATH=%PROJECT_DIR%\osrm-deps\libs\bin;%PATH%
ECHO running engine-tests.exe ...
-%Configuration%\engine-tests.exe
+%Configuration%\unit_tests\engine-tests.exe
IF %ERRORLEVEL% NEQ 0 GOTO ERROR
ECHO running extractor-tests.exe ...
-%Configuration%\extractor-tests.exe
+%Configuration%\unit_tests\extractor-tests.exe
IF %ERRORLEVEL% NEQ 0 GOTO ERROR
ECHO running util-tests.exe ...
-%Configuration%\util-tests.exe
+%Configuration%\unit_tests\util-tests.exe
IF %ERRORLEVEL% NEQ 0 GOTO ERROR
IF NOT "%APPVEYOR_REPO_BRANCH%"=="develop" GOTO DONE
diff --git a/cmake/pkgconfig.in b/cmake/pkgconfig.in
index 92fe403..c85a076 100644
--- a/cmake/pkgconfig.in
+++ b/cmake/pkgconfig.in
@@ -1,5 +1,5 @@
prefix=@CMAKE_INSTALL_PREFIX@
-includedir=${prefix}/include ${prefix}/include/osrm
+includedir=${prefix}/include
libdir=${prefix}/lib
Name: libOSRM
@@ -8,4 +8,4 @@ Version: v at OSRM_VERSION_MAJOR@. at OSRM_VERSION_MINOR@. at OSRM_VERSION_PATCH@
Requires:
Libs: -L${libdir} -losrm
Libs.private: @ENGINE_LIBRARY_LISTING@
-Cflags: -I${includedir}
+Cflags: -I${includedir} -I${includedir}/osrm
diff --git a/cucumber.js b/cucumber.js
index c16104c..5a87dd7 100644
--- a/cucumber.js
+++ b/cucumber.js
@@ -1,6 +1,6 @@
module.exports = {
- default: '--require features --tags ~@todo --tags ~@bug --tags ~@stress --tags ~@guidance',
- verify: '--require features --tags ~@todo --tags ~@bug --tags ~@stress -f progress --tags ~@guidance',
+ default: '--require features --tags ~@stress --tags ~@todo',
+ verify: '--require features --tags ~@todo --tags ~@bug --tags ~@stress -f progress',
jenkins: '--require features --tags ~@todo --tags ~@bug --tags ~@stress --tags ~@options -f progress',
bugs: '--require features --tags @bug',
todo: '--require features --tags @todo',
diff --git a/features/bicycle/access.feature b/features/bicycle/access.feature
index 3a2fffb..67c8180 100644
--- a/features/bicycle/access.feature
+++ b/features/bicycle/access.feature
@@ -5,7 +5,7 @@ Feature: Bike - Access tags on ways
Background:
Given the profile "bicycle"
- Scenario: Bike - Access tag hierachy on ways
+ Scenario: Bike - Access tag hierarchy on ways
Then routability should be
| highway | access | vehicle | bicycle | bothw |
| | | | | x |
@@ -121,6 +121,7 @@ Feature: Bike - Access tags on ways
| private | | | |
| agricultural | | | |
| forestry | | | |
+ | delivery | | | |
| | yes | | x |
| | permissive | | x |
| | designated | | x |
@@ -129,6 +130,7 @@ Feature: Bike - Access tags on ways
| | private | | |
| | agricultural | | |
| | forestry | | |
+ | | delivery | | |
| | | yes | x |
| | | permissive | x |
| | | designated | x |
@@ -137,6 +139,7 @@ Feature: Bike - Access tags on ways
| | | private | |
| | | agricultural | |
| | | forestry | |
+ | | | delivery | |
Scenario: Bike - Access tags on both node and way
Then routability should be
diff --git a/features/bicycle/access_node.feature b/features/bicycle/access_node.feature
index 05e94fe..3c1a75a 100644
--- a/features/bicycle/access_node.feature
+++ b/features/bicycle/access_node.feature
@@ -5,7 +5,7 @@ Feature: Bike - Access tags on nodes
Background:
Given the profile "bicycle"
- Scenario: Bike - Access tag hierachy on nodes
+ Scenario: Bike - Access tag hierarchy on nodes
Then routability should be
| node/access | node/vehicle | node/bicycle | node/highway | bothw |
| | | | | x |
@@ -47,6 +47,7 @@ Feature: Bike - Access tags on nodes
| private | | | |
| agricultural | | | |
| forestry | | | |
+ | delivery | | | |
| | yes | | x |
| | permissive | | x |
| | designated | | x |
@@ -55,6 +56,7 @@ Feature: Bike - Access tags on nodes
| | private | | |
| | agricultural | | |
| | forestry | | |
+ | | delivery | | |
| | | yes | x |
| | | permissive | x |
| | | designated | x |
@@ -63,3 +65,4 @@ Feature: Bike - Access tags on nodes
| | | private | |
| | | agricultural | |
| | | forestry | |
+ | | | delivery | |
diff --git a/features/bicycle/destination.feature b/features/bicycle/destination.feature
index 9c71198..c3a0173 100644
--- a/features/bicycle/destination.feature
+++ b/features/bicycle/destination.feature
@@ -19,15 +19,15 @@ Feature: Bike - Destination only, no passing through
| axye | |
When I route I should get
- | from | to | route |
- | a | b | ab |
- | a | c | ab,bcd |
- | a | d | ab,bcd |
- | a | e | axye |
- | e | d | de |
- | e | c | de,bcd |
- | e | b | de,bcd |
- | e | a | axye |
+ | from | to | route |
+ | a | b | ab,ab |
+ | a | c | ab,bcd,bcd |
+ | a | d | ab,bcd,bcd |
+ | a | e | axye,axye |
+ | e | d | de,de |
+ | e | c | de,bcd,bcd |
+ | e | b | de,bcd,bcd |
+ | e | a | axye,axye |
Scenario: Bike - Destination only street
Given the node map
@@ -45,15 +45,15 @@ Feature: Bike - Destination only, no passing through
| axye | |
When I route I should get
- | from | to | route |
- | a | b | ab |
- | a | c | ab,bc |
- | a | d | ab,bc,cd |
- | a | e | axye |
- | e | d | de |
- | e | c | de,dc |
- | e | b | de,dc,bc |
- | e | a | axye |
+ | from | to | route |
+ | a | b | ab,ab |
+ | a | c | ab,bc,bc |
+ | a | d | ab,bc,cd,cd |
+ | a | e | axye,axye |
+ | e | d | de,de |
+ | e | c | de,cd,cd |
+ | e | b | de,cd,bc,bc |
+ | e | a | axye,axye |
Scenario: Bike - Routing inside a destination only area
Given the node map
@@ -70,8 +70,8 @@ Feature: Bike - Destination only, no passing through
| axye | |
When I route I should get
- | from | to | route |
- | a | e | ab,bc,cd,de |
- | e | a | de,cd,bc,ab |
- | b | d | bc,cd |
- | d | b | cd,bc |
+ | from | to | route |
+ | a | e | ab,bc,cd,de,de |
+ | e | a | de,cd,bc,ab,ab |
+ | b | d | bc,cd,cd |
+ | d | b | cd,bc,bc |
diff --git a/features/bicycle/mode.feature b/features/bicycle/mode.feature
index 3587f6c..852402a 100644
--- a/features/bicycle/mode.feature
+++ b/features/bicycle/mode.feature
@@ -16,13 +16,13 @@ Feature: Bike - Mode flag
| cd | primary | | |
When I route I should get
- | from | to | route | turns | modes |
- | a | d | ab,bc,cd,cd | depart,right,left,arrive | cycling,ferry,cycling,cycling |
- | d | a | cd,bc,ab,ab | depart,right,left,arrive | cycling,ferry,cycling,cycling |
- | c | a | bc,ab,ab | depart,left,arrive | ferry,cycling,cycling |
- | d | b | cd,bc,bc | depart,right,arrive | cycling,ferry,ferry |
- | a | c | ab,bc,bc | depart,right,arrive | cycling,ferry,ferry |
- | b | d | bc,cd,cd | depart,left,arrive | ferry,cycling,cycling |
+ | from | to | route | modes |
+ | a | d | ab,bc,cd,cd | cycling,ferry,cycling,cycling |
+ | d | a | cd,bc,ab,ab | cycling,ferry,cycling,cycling |
+ | c | a | bc,ab,ab | ferry,cycling,cycling |
+ | d | b | cd,bc,bc | cycling,ferry,ferry |
+ | a | c | ab,bc,bc | cycling,ferry,ferry |
+ | b | d | bc,cd,cd | ferry,cycling,cycling |
Scenario: Bike - Mode when using a train
Given the node map
@@ -36,13 +36,13 @@ Feature: Bike - Mode flag
| cd | primary | | |
When I route I should get
- | from | to | route | turns | modes |
- | a | d | ab,bc,cd,cd | depart,right,left,arrive | cycling,train,cycling,cycling |
- | d | a | cd,bc,ab,ab | depart,right,left,arrive | cycling,train,cycling,cycling |
- | c | a | bc,ab,ab | depart,left,arrive | train,cycling,cycling |
- | d | b | cd,bc,bc | depart,right,arrive | cycling,train,train |
- | a | c | ab,bc,bc | depart,right,arrive | cycling,train,train |
- | b | d | bc,cd,cd | depart,left,arrive | train,cycling,cycling |
+ | from | to | route | modes |
+ | a | d | ab,bc,cd,cd | cycling,train,cycling,cycling |
+ | d | a | cd,bc,ab,ab | cycling,train,cycling,cycling |
+ | c | a | bc,ab,ab | train,cycling,cycling |
+ | d | b | cd,bc,bc | cycling,train,train |
+ | a | c | ab,bc,bc | cycling,train,train |
+ | b | d | bc,cd,cd | train,cycling,cycling |
Scenario: Bike - Mode when pushing bike against oneways
Given the node map
@@ -56,13 +56,13 @@ Feature: Bike - Mode flag
| cd | primary | |
When I route I should get
- | from | to | route | turns | modes |
- | a | d | ab,bc,cd,cd | depart,right,left,arrive | cycling,cycling,cycling,cycling |
- | d | a | cd,bc,ab,ab | depart,right,left,arrive | cycling,pushing bike,cycling,cycling |
- | c | a | bc,ab,ab | depart,left,arrive | pushing bike,cycling,cycling |
- | d | b | cd,bc,bc | depart,right,arrive | cycling,pushing bike,pushing bike |
- | a | c | ab,bc,bc | depart,right,arrive | cycling,cycling,cycling |
- | b | d | bc,cd,cd | depart,left,arrive | cycling,cycling,cycling |
+ | from | to | route | modes |
+ | a | d | ab,bc,cd,cd | cycling,cycling,cycling,cycling |
+ | d | a | cd,bc,ab,ab | cycling,pushing bike,cycling,cycling |
+ | c | a | bc,ab,ab | pushing bike,cycling,cycling |
+ | d | b | cd,bc,bc | cycling,pushing bike,pushing bike |
+ | a | c | ab,bc,bc | cycling,cycling,cycling |
+ | b | d | bc,cd,cd | cycling,cycling,cycling |
Scenario: Bike - Mode when pushing on pedestrain streets
Given the node map
@@ -76,13 +76,13 @@ Feature: Bike - Mode flag
| cd | primary |
When I route I should get
- | from | to | route | turns | modes |
- | a | d | ab,bc,cd,cd | depart,right,left,arrive | cycling,pushing bike,cycling,cycling |
- | d | a | cd,bc,ab,ab | depart,right,left,arrive | cycling,pushing bike,cycling,cycling |
- | c | a | bc,ab,ab | depart,left,arrive | pushing bike,cycling,cycling |
- | d | b | cd,bc,bc | depart,right,arrive | cycling,pushing bike,pushing bike |
- | a | c | ab,bc,bc | depart,right,arrive | cycling,pushing bike,pushing bike |
- | b | d | bc,cd,cd | depart,left,arrive | pushing bike,cycling,cycling |
+ | from | to | route | modes |
+ | a | d | ab,bc,cd,cd | cycling,pushing bike,cycling,cycling |
+ | d | a | cd,bc,ab,ab | cycling,pushing bike,cycling,cycling |
+ | c | a | bc,ab,ab | pushing bike,cycling,cycling |
+ | d | b | cd,bc,bc | cycling,pushing bike,pushing bike |
+ | a | c | ab,bc,bc | cycling,pushing bike,pushing bike |
+ | b | d | bc,cd,cd | pushing bike,cycling,cycling |
Scenario: Bike - Mode when pushing on pedestrain areas
Given the node map
@@ -116,13 +116,13 @@ Feature: Bike - Mode flag
| cd | primary |
When I route I should get
- | from | to | route | turns | modes |
- | a | d | ab,bc,cd,cd | depart,right,left,arrive | cycling,pushing bike,cycling,cycling |
- | d | a | cd,bc,ab,ab | depart,right,left,arrive | cycling,pushing bike,cycling,cycling |
- | c | a | bc,ab,ab | depart,left,arrive | pushing bike,cycling,cycling |
- | d | b | cd,bc,bc | depart,right,arrive | cycling,pushing bike,pushing bike |
- | a | c | ab,bc,bc | depart,right,arrive | cycling,pushing bike,pushing bike |
- | b | d | bc,cd,cd | depart,left,arrive | pushing bike,cycling,cycling |
+ | from | to | route | modes |
+ | a | d | ab,bc,cd,cd | cycling,pushing bike,cycling,cycling |
+ | d | a | cd,bc,ab,ab | cycling,pushing bike,cycling,cycling |
+ | c | a | bc,ab,ab | pushing bike,cycling,cycling |
+ | d | b | cd,bc,bc | cycling,pushing bike,pushing bike |
+ | a | c | ab,bc,bc | cycling,pushing bike,pushing bike |
+ | b | d | bc,cd,cd | pushing bike,cycling,cycling |
Scenario: Bike - Mode when bicycle=dismount
Given the node map
@@ -136,13 +136,13 @@ Feature: Bike - Mode flag
| cd | primary | |
When I route I should get
- | from | to | route | turns | modes |
- | a | d | ab,bc,cd,cd | depart,right,left,arrive | cycling,pushing bike,cycling,cycling |
- | d | a | cd,bc,ab,ab | depart,right,left,arrive | cycling,pushing bike,cycling,cycling |
- | c | a | bc,ab,ab | depart,left,arrive | pushing bike,cycling,cycling |
- | d | b | cd,bc,bc | depart,right,arrive | cycling,pushing bike,pushing bike |
- | a | c | ab,bc,bc | depart,right,arrive | cycling,pushing bike,pushing bike |
- | b | d | bc,cd,cd | depart,left,arrive | pushing bike,cycling,cycling |
+ | from | to | route | modes |
+ | a | d | ab,bc,cd,cd | cycling,pushing bike,cycling,cycling |
+ | d | a | cd,bc,ab,ab | cycling,pushing bike,cycling,cycling |
+ | c | a | bc,ab,ab | pushing bike,cycling,cycling |
+ | d | b | cd,bc,bc | cycling,pushing bike,pushing bike |
+ | a | c | ab,bc,bc | cycling,pushing bike,pushing bike |
+ | b | d | bc,cd,cd | pushing bike,cycling,cycling |
Scenario: Bicycle - Modes when starting on forward oneway
Given the node map
diff --git a/features/bicycle/pushing.feature b/features/bicycle/pushing.feature
index 3d00b53..d672821 100644
--- a/features/bicycle/pushing.feature
+++ b/features/bicycle/pushing.feature
@@ -63,7 +63,6 @@ Feature: Bike - Accessability of different way types
| runway | | | |
| runway | yes | foot | foot |
- @todo
Scenario: Bike - Pushing bikes on ways with foot=yes in one direction
Then routability should be
| highway | foot:forward | foot:backward | forw | backw |
@@ -98,13 +97,12 @@ Feature: Bike - Accessability of different way types
| cd | primary | |
When I route I should get
- | from | to | route | turns |
- | a | d | ab,bc,cd,cd | depart,right,left,arrive |
- | d | a | cd,bc,ab,ab | depart,right,left,arrive |
- | c | a | bc,ab,ab | depart,left,arrive |
- | d | b | cd,bc,bc | depart,right,arrive |
+ | from | to | route | modes |
+ | a | d | ab,bc,cd,cd | cycling,cycling,cycling,cycling |
+ | d | a | cd,bc,ab,ab | cycling,pushing bike,cycling,cycling |
+ | c | a | bc,ab,ab | pushing bike,cycling,cycling |
+ | d | b | cd,bc,bc | cycling,pushing bike,pushing bike |
- @todo
Scenario: Bike - Instructions when pushing bike on footway/pedestrian, etc.
Given the node map
| a | b | |
@@ -117,8 +115,8 @@ Feature: Bike - Accessability of different way types
| cd | primary |
When I route I should get
- | from | to | route | turns |
- | a | d | ab,bc,cd,cd | depart,right,left,arrive |
- | d | a | cd,bc,ab,ab | depart,right,left,arrive |
- | c | a | bc,ab,ab | depart,left,arrive |
- | d | b | cd,bc,bc | depart,right,arrive |
+ | from | to | route | modes |
+ | a | d | ab,bc,cd,cd | cycling,pushing bike,cycling,cycling |
+ | d | a | cd,bc,ab,ab | cycling,pushing bike,cycling,cycling |
+ | c | a | bc,ab,ab | pushing bike,cycling,cycling |
+ | d | b | cd,bc,bc | cycling,pushing bike,pushing bike |
diff --git a/features/bicycle/roundabout.feature b/features/bicycle/roundabout.feature
deleted file mode 100644
index 2e0d099..0000000
--- a/features/bicycle/roundabout.feature
+++ /dev/null
@@ -1,30 +0,0 @@
- at routing @bicycle @roundabout @instruction
-Feature: Roundabout Instructions
-
- Background:
- Given the profile "bicycle"
-
- Scenario: Bicycle - Roundabout instructions
- Given the node map
- | | | v | | |
- | | | d | | |
- | s | a | | c | u |
- | | | b | | |
- | | | t | | |
-
- And the ways
- | nodes | junction |
- | sa | |
- | tb | |
- | uc | |
- | vd | |
- | abcda | roundabout |
-
- When I route I should get
- | from | to | route | turns |
- | s | t | sa,tb,tb | depart,roundabout-exit-1,arrive |
- | s | u | sa,uc,uc | depart,roundabout-exit-2,arrive |
- | s | v | sa,vd,vd | depart,roundabout-exit-3,arrive |
- | u | v | uc,vd,vd | depart,roundabout-exit-1,arrive |
- | u | s | uc,sa,sa | depart,roundabout-exit-2,arrive |
- | u | t | uc,tb,tb | depart,roundabout-exit-3,arrive |
diff --git a/features/car/access.feature b/features/car/access.feature
index 8f05ccb..93691d4 100644
--- a/features/car/access.feature
+++ b/features/car/access.feature
@@ -5,7 +5,7 @@ Feature: Car - Restricted access
Background:
Given the profile "car"
- Scenario: Car - Access tag hierachy on ways
+ Scenario: Car - Access tag hierarchy on ways
Then routability should be
| access | vehicle | motor_vehicle | motorcar | bothw |
| | | | | x |
@@ -30,7 +30,7 @@ Feature: Car - Restricted access
| | | no | yes | x |
| | | yes | no | |
- Scenario: Car - Access tag hierachy on nodes
+ Scenario: Car - Access tag hierarchy on nodes
Then routability should be
| node/access | node/vehicle | node/motor_vehicle | node/motorcar | bothw |
| | | | | x |
@@ -94,6 +94,7 @@ Feature: Car - Restricted access
| agricultural | |
| forestry | |
| psv | |
+ | delivery | |
| some_tag | x |
@@ -108,6 +109,7 @@ Feature: Car - Restricted access
| agricultural | |
| forestry | |
| psv | |
+ | delivery | |
| some_tag | x |
Scenario: Car - Access tags on both node and way
diff --git a/features/car/destination.feature b/features/car/destination.feature
index 506aa21..3bf0733 100644
--- a/features/car/destination.feature
+++ b/features/car/destination.feature
@@ -19,15 +19,15 @@ Feature: Car - Destination only, no passing through
| axye | |
When I route I should get
- | from | to | route |
- | a | b | ab |
- | a | c | ab,bcd |
- | a | d | ab,bcd |
- | a | e | axye |
- | e | d | de |
- | e | c | de,bcd |
- | e | b | de,bcd |
- | e | a | axye |
+ | from | to | route |
+ | a | b | ab,ab |
+ | a | c | ab,bcd,bcd |
+ | a | d | ab,bcd,bcd |
+ | a | e | axye,axye |
+ | e | d | de,de |
+ | e | c | de,bcd,bcd |
+ | e | b | de,bcd,bcd |
+ | e | a | axye,axye |
Scenario: Car - Destination only street
Given the node map
@@ -45,15 +45,15 @@ Feature: Car - Destination only, no passing through
| axye | |
When I route I should get
- | from | to | route |
- | a | b | ab |
- | a | c | ab,bc |
- | a | d | ab,bc,cd |
- | a | e | axye |
- | e | d | de |
- | e | c | de,dc |
- | e | b | de,dc,bc |
- | e | a | axye |
+ | from | to | route |
+ | a | b | ab,ab |
+ | a | c | ab,bc,bc |
+ | a | d | ab,bc,cd,cd |
+ | a | e | axye,axye |
+ | e | d | de,de |
+ | e | c | de,cd,cd |
+ | e | b | de,cd,bc,bc |
+ | e | a | axye,axye |
Scenario: Car - Routing inside a destination only area
Given the node map
@@ -70,8 +70,8 @@ Feature: Car - Destination only, no passing through
| axye | |
When I route I should get
- | from | to | route |
- | a | e | ab,bc,cd,de |
- | e | a | de,cd,bc,ab |
- | b | d | bc,cd |
- | d | b | cd,bc |
+ | from | to | route |
+ | a | e | ab,bc,cd,de,de |
+ | e | a | de,cd,bc,ab,ab |
+ | b | d | bc,cd,cd |
+ | d | b | cd,bc,bc |
diff --git a/features/car/mode.feature b/features/car/mode.feature
index f390982..e0feff1 100644
--- a/features/car/mode.feature
+++ b/features/car/mode.feature
@@ -15,13 +15,13 @@ Feature: Car - Mode flag
| cd | primary | | |
When I route I should get
- | from | to | route | turns | modes |
- | a | d | ab,bc,cd,cd | depart,right,left,arrive | driving,ferry,driving,driving |
- | d | a | cd,bc,ab,ab | depart,right,left,arrive | driving,ferry,driving,driving |
- | c | a | bc,ab,ab | depart,left,arrive | ferry,driving,driving |
- | d | b | cd,bc,bc | depart,right,arrive | driving,ferry,ferry |
- | a | c | ab,bc,bc | depart,right,arrive | driving,ferry,ferry |
- | b | d | bc,cd,cd | depart,left,arrive | ferry,driving,driving |
+ | from | to | route | modes |
+ | a | d | ab,bc,cd,cd | driving,ferry,driving,driving |
+ | d | a | cd,bc,ab,ab | driving,ferry,driving,driving |
+ | c | a | bc,ab,ab | ferry,driving,driving |
+ | d | b | cd,bc,bc | driving,ferry,ferry |
+ | a | c | ab,bc,bc | driving,ferry,ferry |
+ | b | d | bc,cd,cd | ferry,driving,driving |
Scenario: Car - Snapping when using a ferry
Given the node map
@@ -34,7 +34,7 @@ Feature: Car - Mode flag
| ef | primary | | |
When I route I should get
- | from | to | route | turns | modes | time |
- | c | d | bcde,bcde | depart,arrive | ferry,ferry | 600s |
+ | from | to | route | modes | time |
+ | c | d | bcde,bcde | ferry,ferry | 600s |
diff --git a/features/car/roundabout.feature b/features/car/roundabout.feature
deleted file mode 100644
index beb5d4e..0000000
--- a/features/car/roundabout.feature
+++ /dev/null
@@ -1,30 +0,0 @@
- at routing @car @roundabout @instruction
-Feature: Roundabout Instructions
-
- Background:
- Given the profile "car"
-
- Scenario: Car - Roundabout instructions
- Given the node map
- | | | v | | |
- | | | d | | |
- | s | a | | c | u |
- | | | b | | |
- | | | t | | |
-
- And the ways
- | nodes | junction |
- | sa | |
- | tb | |
- | uc | |
- | vd | |
- | abcda | roundabout |
-
- When I route I should get
- | from | to | route | turns |
- | s | t | sa,tb,tb | depart,roundabout-exit-1,arrive |
- | s | u | sa,uc,uc | depart,roundabout-exit-2,arrive |
- | s | v | sa,vd,vd | depart,roundabout-exit-3,arrive |
- | u | v | uc,vd,vd | depart,roundabout-exit-1,arrive |
- | u | s | uc,sa,sa | depart,roundabout-exit-2,arrive |
- | u | t | uc,tb,tb | depart,roundabout-exit-3,arrive |
diff --git a/features/foot/access.feature b/features/foot/access.feature
index 353076c..4642a3b 100644
--- a/features/foot/access.feature
+++ b/features/foot/access.feature
@@ -5,7 +5,7 @@ Feature: Foot - Access tags on ways
Background:
Given the profile "foot"
- Scenario: Foot - Access tag hierachy on ways
+ Scenario: Foot - Access tag hierarchy on ways
Then routability should be
| highway | access | foot | bothw |
| footway | | | x |
@@ -52,6 +52,7 @@ Feature: Foot - Access tags on ways
| private | | |
| agricultural | | |
| forestry | | |
+ | delivery | | |
| | yes | x |
| | permissive | x |
| | designated | x |
@@ -60,6 +61,7 @@ Feature: Foot - Access tags on ways
| | private | |
| | agricultural | |
| | forestry | |
+ | | delivery | |
Scenario: Foot - Access tags on both node and way
Then routability should be
diff --git a/features/foot/access_node.feature b/features/foot/access_node.feature
index 8519d05..8dc0ebe 100644
--- a/features/foot/access_node.feature
+++ b/features/foot/access_node.feature
@@ -5,7 +5,7 @@ Feature: Foot - Access tags on nodes
Background:
Given the profile "foot"
- Scenario: Foot - Access tag hierachy on nodes
+ Scenario: Foot - Access tag hierarchy on nodes
Then routability should be
| node/access | node/foot | bothw |
| | | x |
@@ -40,6 +40,7 @@ Feature: Foot - Access tags on nodes
| private | | |
| agricultural | | |
| forestry | | |
+ | delivery | | |
| no | yes | x |
| no | permissive | x |
| no | designated | x |
@@ -48,3 +49,4 @@ Feature: Foot - Access tags on nodes
| yes | private | |
| yes | agricultural | |
| yes | forestry | |
+ | yes | delivery | |
diff --git a/features/guidance/continue.feature b/features/guidance/continue.feature
new file mode 100644
index 0000000..b3abe48
--- /dev/null
+++ b/features/guidance/continue.feature
@@ -0,0 +1,90 @@
+ at routing @guidance
+Feature: Continue Instructions
+
+ Background:
+ Given the profile "car"
+ Given a grid size of 10 meters
+
+ Scenario: Road turning left
+ Given the node map
+ | | | c | |
+ | a | | b | d |
+
+ And the ways
+ | nodes | highway |
+ | abc | primary |
+ | bd | primary |
+
+ When I route I should get
+ | waypoints | route | turns |
+ | a,c | abc,abc,abc | depart,continue left,arrive |
+ | a,d | abc,bd,bd | depart,new name straight,arrive |
+
+ Scenario: Road turning right
+ Given the node map
+ | a | | b | d |
+ | | | c | |
+
+ And the ways
+ | nodes | highway |
+ | abc | primary |
+ | bd | primary |
+
+ When I route I should get
+ | waypoints | route | turns |
+ | a,c | abc,abc,abc | depart,continue right,arrive |
+ | a,d | abc,bd,bd | depart,new name straight,arrive |
+
+ Scenario: Road turning slight left
+ Given the node map
+ | | | | | c |
+ | | | | | |
+ | a | | b | | |
+ | | | | d | |
+
+ And the ways
+ | nodes | highway |
+ | abc | primary |
+ | bd | primary |
+
+ When I route I should get
+ | waypoints | route | turns |
+ | a,c | abc,abc,abc | depart,continue left,arrive |
+ | a,d | abc,bd,bd | depart,turn right,arrive |
+
+ Scenario: Road turning slight right
+ Given the node map
+ | | | | d | |
+ | a | | b | | |
+ | | | | | |
+ | | | | | c |
+
+ And the ways
+ | nodes | highway |
+ | abc | primary |
+ | bd | primary |
+
+ When I route I should get
+ | waypoints | route | turns |
+ | a,c | abc,abc,abc | depart,continue right,arrive |
+ | a,d | abc,bd,bd | depart,turn left,arrive |
+
+ Scenario: Road Loop
+ Given the node map
+ | | | f | | e |
+ | | | | | |
+ | a | | b | g | |
+ | | | | | |
+ | | | c | | d |
+
+ And the ways
+ | nodes | highway |
+ | abcdefb | primary |
+ | bg | primary |
+
+ When I route I should get
+ | waypoints | route | turns |
+ | a,c | abcdefb,abcdefb,abcdefb | depart,continue right,arrive |
+ | a,f | abcdefb,abcdefb,abcdefb | depart,continue left,arrive |
+ | a,d | abcdefb,abcdefb,abcdefb | depart,continue right,arrive |
+ | a,e | abcdefb,abcdefb,abcdefb | depart,continue left,arrive |
diff --git a/features/guidance/end-of-road.feature b/features/guidance/end-of-road.feature
new file mode 100644
index 0000000..7f8231b
--- /dev/null
+++ b/features/guidance/end-of-road.feature
@@ -0,0 +1,106 @@
+ at routing @guidance
+Feature: End Of Road Instructions
+
+ Background:
+ Given the profile "car"
+ Given a grid size of 10 meters
+
+ Scenario: End of Road with through street
+ Given the node map
+ | | | c |
+ | a | | b |
+ | | | d |
+
+ And the ways
+ | nodes | highway |
+ | ab | primary |
+ | cbd | primary |
+
+ When I route I should get
+ | waypoints | route | turns |
+ | a,c | ab,cbd,cbd | depart,end of road left,arrive |
+ | a,d | ab,cbd,cbd | depart,end of road right,arrive |
+
+
+ Scenario: End of Road with three streets
+ Given the node map
+ | | | c |
+ | a | | b |
+ | | | d |
+
+ And the ways
+ | nodes | highway |
+ | ab | primary |
+ | cb | primary |
+ | bd | primary |
+
+ When I route I should get
+ | waypoints | route | turns |
+ | a,c | ab,cb,cb | depart,end of road left,arrive |
+ | a,d | ab,bd,bd | depart,end of road right,arrive |
+
+ Scenario: End of Road with three streets, slightly angled
+ Given the node map
+ | a | | | | | c |
+ | | | | | | b |
+ | | | | | | d |
+
+ And the ways
+ | nodes | highway |
+ | ab | primary |
+ | cb | primary |
+ | bd | primary |
+
+ When I route I should get
+ | waypoints | route | turns |
+ | a,c | ab,cb,cb | depart,end of road left,arrive |
+ | a,d | ab,bd,bd | depart,end of road right,arrive |
+
+ Scenario: End of Road with three streets, slightly angled
+ Given the node map
+ | | | | | | c |
+ | | | | | | b |
+ | a | | | | | d |
+
+ And the ways
+ | nodes | highway |
+ | ab | primary |
+ | cb | primary |
+ | bd | primary |
+
+ When I route I should get
+ | waypoints | route | turns |
+ | a,c | ab,cb,cb | depart,end of road left,arrive |
+ | a,d | ab,bd,bd | depart,end of road right,arrive |
+
+ Scenario: End of Road with through street, slightly angled
+ Given the node map
+ | a | | | | | c |
+ | | | | | | b |
+ | | | | | | d |
+
+ And the ways
+ | nodes | highway |
+ | ab | primary |
+ | cbd | primary |
+
+ When I route I should get
+ | waypoints | route | turns |
+ | a,c | ab,cbd,cbd | depart,end of road left,arrive |
+ | a,d | ab,cbd,cbd | depart,end of road right,arrive |
+
+ Scenario: End of Road with through street, slightly angled
+ Given the node map
+ | | | | | | c |
+ | | | | | | b |
+ | a | | | | | d |
+
+ And the ways
+ | nodes | highway |
+ | ab | primary |
+ | cbd | primary |
+
+ When I route I should get
+ | waypoints | route | turns |
+ | a,c | ab,cbd,cbd | depart,end of road left,arrive |
+ | a,d | ab,cbd,cbd | depart,end of road right,arrive |
diff --git a/features/guidance/fork.feature b/features/guidance/fork.feature
new file mode 100644
index 0000000..7b78a28
--- /dev/null
+++ b/features/guidance/fork.feature
@@ -0,0 +1,213 @@
+ at routing @guidance
+Feature: Fork Instructions
+
+ Background:
+ Given the profile "car"
+ Given a grid size of 10 meters
+
+ Scenario: Fork Same Road Class
+ Given the node map
+ | | | | | c |
+ | a | | b | | |
+ | | | | | d |
+
+ And the ways
+ | nodes | highway |
+ | ab | primary |
+ | bc | primary |
+ | bd | primary |
+
+ When I route I should get
+ | waypoints | route | turns |
+ | a,c | ab,bc,bc | depart,fork slight left,arrive |
+ | a,d | ab,bd,bd | depart,fork slight right,arrive |
+
+ Scenario: Do not fork on link type
+ Given the node map
+ | | | | | c |
+ | a | | b | | |
+ | | | | | d |
+
+ And the ways
+ | nodes | highway |
+ | abc | primary |
+ | bd | primary_link |
+
+
+ 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 |
+
+ Scenario: Fork in presence of other roads
+ Given the node map
+ | | | | | c |
+ | a | | b | | |
+ | | e | | | d |
+
+ And the ways
+ | nodes | highway |
+ | ab | primary |
+ | bc | primary |
+ | bd | primary |
+ | eb | primary |
+
+ When I route I should get
+ | waypoints | route | turns |
+ | a,c | ab,bc,bc | depart,fork slight left,arrive |
+ | a,d | ab,bd,bd | depart,fork slight right,arrive |
+
+ Scenario: Fork Turning Slight Left
+ Given the node map
+ | | | | | | c |
+ | | | | | | |
+ | a | | b | | | |
+ | | | | | d | |
+
+ And the ways
+ | nodes | highway |
+ | ab | primary |
+ | bc | primary |
+ | bd | primary |
+
+ When I route I should get
+ | waypoints | route | turns |
+ | a,c | ab,bc,bc | depart,fork slight left,arrive |
+ | a,d | ab,bd,bd | depart,fork slight right,arrive |
+
+ Scenario: Fork Turning Slight Right
+ Given the node map
+ | | | | | c | |
+ | a | | b | | | |
+ | | | | | | |
+ | | | | | | d |
+
+ And the ways
+ | nodes | highway |
+ | ab | primary |
+ | bc | primary |
+ | bd | primary |
+
+ When I route I should get
+ | waypoints | route | turns |
+ | a,c | ab,bc,bc | depart,fork slight left,arrive |
+ | a,d | ab,bd,bd | depart,fork slight right,arrive |
+
+ Scenario: Do not fork on service
+ Given the node map
+ | | | | | c |
+ | a | | b | | |
+ | | | | | d |
+
+ And the ways
+ | nodes | highway |
+ | abc | residential |
+ | bd | service |
+
+ 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 |
+
+ Scenario: Fork Both Turning Slight Right
+ Given the node map
+ | a | | b | | | |
+ | | | | | | c |
+ | | | | | | d |
+
+ And the ways
+ | nodes | highway |
+ | ab | primary |
+ | bc | primary |
+ | bd | primary |
+
+ When I route I should get
+ | waypoints | route | turns |
+ | a,c | ab,bc,bc | depart,fork slight left,arrive |
+ | a,d | ab,bd,bd | depart,fork slight right,arrive |
+
+ Scenario: Fork Both Turning Slight Left
+ Given the node map
+ | | | | | | c |
+ | | | | | | d |
+ | a | | b | | | |
+
+ And the ways
+ | nodes | highway |
+ | ab | primary |
+ | bc | primary |
+ | bd | primary |
+
+ When I route I should get
+ | waypoints | route | turns |
+ | a,c | ab,bc,bc | depart,fork slight left,arrive |
+ | a,d | ab,bd,bd | depart,fork slight right,arrive |
+
+ Scenario: Fork Both Turning Slight Right - Unnamed
+ Given the node map
+ | a | | b | | | |
+ | | | | | | c |
+ | | | | | | d |
+
+ And the ways
+ | nodes | highway | name |
+ | ab | primary | |
+ | bc | primary | |
+ | bd | primary | |
+
+ When I route I should get
+ | waypoints | route | turns |
+ | a,c | ,, | depart,fork slight left,arrive |
+ | a,d | ,, | depart,fork slight right,arrive |
+
+ Scenario: Fork Both Turning Slight Left - Unnamed
+ Given the node map
+ | | | | | | c |
+ | | | | | | d |
+ | a | | b | | | |
+
+ And the ways
+ | nodes | highway | name |
+ | ab | primary | |
+ | bc | primary | |
+ | bd | primary | |
+
+ When I route I should get
+ | waypoints | route | turns |
+ | a,c | ,, | depart,fork slight left,arrive |
+ | a,d | ,, | depart,fork slight right,arrive |
+
+ Scenario: Fork Both Turning Very Slightly Right - Unnamed
+ Given the node map
+ | a | | b | | | | | | | | | | | | | | | |
+ | | | | | | | | | | | | c | | | | | | |
+ | | | | | | | | | | | | | | | | | | d |
+
+ And the ways
+ | nodes | highway | name |
+ | ab | primary | |
+ | bc | primary | |
+ | bd | primary | |
+
+ When I route I should get
+ | waypoints | route | turns |
+ | a,c | ,, | depart,fork slight left,arrive |
+ | a,d | ,, | depart,fork slight right,arrive |
+
+ Scenario: Fork Both Turning Very Slightly Right - Unnamed Ramps
+ Given the node map
+ | a | | b | | | | | | | | | | | | | | | |
+ | | | | | | | | | | | | c | | | | | | |
+ | | | | | | | | | | | | | | | | | | d |
+
+ And the ways
+ | nodes | highway | name |
+ | ab | motorway_link | |
+ | bc | motorway_link | |
+ | bd | motorway_link | |
+
+ When I route I should get
+ | waypoints | route | turns |
+ | a,c | ,, | depart,fork slight left,arrive |
+ | a,d | ,, | depart,fork slight right,arrive |
+
diff --git a/features/guidance/merge.feature b/features/guidance/merge.feature
new file mode 100644
index 0000000..0736e8f
--- /dev/null
+++ b/features/guidance/merge.feature
@@ -0,0 +1,52 @@
+ at routing @guidance
+Feature: Merging
+
+ Background:
+ Given the profile "car"
+ Given a grid size of 10 meters
+
+ Scenario: Merge on Four Way Intersection
+ Given the node map
+ | d | | |
+ | a | b | c |
+ | e | | |
+
+ And the ways
+ | nodes | highway |
+ | abc | primary |
+ | db | primary |
+ | eb | primary |
+
+ When I route I should get
+ | waypoints | route | turns |
+ | d,c | db,abc,abc | depart,merge slight right,arrive |
+ | e,c | eb,abc,abc | depart,merge slight left,arrive |
+
+ Scenario: Merge on Three Way Intersection Right
+ Given the node map
+ | d | | |
+ | a | b | c |
+
+ And the ways
+ | nodes | highway |
+ | abc | primary |
+ | db | primary |
+
+ When I route I should get
+ | waypoints | route | turns |
+ | d,c | db,abc,abc | depart,merge slight right,arrive |
+
+ Scenario: Merge on Three Way Intersection Right
+ Given the node map
+ | a | b | c |
+ | d | | |
+
+ And the ways
+ | nodes | highway |
+ | abc | primary |
+ | db | primary |
+
+ When I route I should get
+ | waypoints | route | turns |
+ | d,c | db,abc,abc | depart,merge slight left,arrive |
+
diff --git a/features/guidance/motorway.feature b/features/guidance/motorway.feature
index bcde322..5e9b312 100644
--- a/features/guidance/motorway.feature
+++ b/features/guidance/motorway.feature
@@ -1,8 +1,8 @@
@routing @guidance
-Feature: Basic Roundabout
+Feature: Motorway Guidance
Background:
- Given the profile "testbot"
+ Given the profile "car"
Given a grid size of 10 meters
Scenario: Ramp Exit Right
@@ -16,9 +16,9 @@ Feature: Basic Roundabout
| bfg | motorway_link |
When I route I should get
- | waypoints | route | turns |
- | a,e | abcde, abcde | depart, arrive |
- | a,g | abcde, bfg, bfg | depart, ramp-slight-right, arrive |
+ | waypoints | route | turns |
+ | a,e | abcde,abcde | depart,arrive |
+ | a,g | abcde,bfg,bfg | depart,ramp slight right,arrive |
Scenario: Ramp Exit Right Curved Right
Given the node map
@@ -32,9 +32,9 @@ Feature: Basic Roundabout
| bfg | motorway_link |
When I route I should get
- | waypoints | route | turns |
- | a,e | abcde, abcde | depart, arrive |
- | a,g | abcde, bfg, bfg | depart, ramp-slight-right, arrive |
+ | waypoints | route | turns |
+ | a,e | abcde,abcde | depart,arrive |
+ | a,g | abcde,bfg,bfg | depart,ramp right,arrive |
Scenario: Ramp Exit Right Curved Left
Given the node map
@@ -49,9 +49,9 @@ Feature: Basic Roundabout
| cfg | motorway_link |
When I route I should get
- | waypoints | route | turns |
- | a,e | abcde, abcde | depart, arrive |
- | a,g | abcde, cfg, cfg | depart, ramp-slight-right, arrive |
+ | waypoints | route | turns |
+ | a,e | abcde,abcde | depart,arrive |
+ | a,g | abcde,cfg,cfg | depart,ramp slight right,arrive |
Scenario: Ramp Exit Left
@@ -65,9 +65,9 @@ Feature: Basic Roundabout
| bfg | motorway_link |
When I route I should get
- | waypoints | route | turns |
- | a,e | abcde, abcde | depart, arrive |
- | a,g | abcde, bfg, bfg | depart, ramp-slight-left, arrive |
+ | waypoints | route | turns |
+ | a,e | abcde,abcde | depart,arrive |
+ | a,g | abcde,bfg,bfg | depart,ramp slight left,arrive |
Scenario: Ramp Exit Left Curved Left
Given the node map
@@ -81,9 +81,9 @@ Feature: Basic Roundabout
| bfg | motorway_link |
When I route I should get
- | waypoints | route | turns |
- | a,e | abcde, abcde | depart, arrive |
- | a,g | abcde, bfg, bfg | depart, ramp-slight-left, arrive |
+ | waypoints | route | turns |
+ | a,e | abcde,abcde | depart,arrive |
+ | a,g | abcde,bfg,bfg | depart,ramp left,arrive |
Scenario: Ramp Exit Left Curved Right
Given the node map
@@ -97,9 +97,9 @@ Feature: Basic Roundabout
| cfg | motorway_link |
When I route I should get
- | waypoints | route | turns |
- | a,e | abcde, abcde | depart, arrive |
- | a,g | abcde, cfg, cfg | depart, ramp-slight-left, arrive |
+ | waypoints | route | turns |
+ | a,e | abcde,abcde | depart,arrive |
+ | a,g | abcde,cfg,cfg | depart,ramp slight left,arrive |
Scenario: On Ramp Right
Given the node map
@@ -112,9 +112,9 @@ Feature: Basic Roundabout
| fgd | motorway_link |
When I route I should get
- | waypoints | route | turns |
- | a,e | abcde, abcde | depart, arrive |
- | f,e | abcde, fgd, fgd | depart, merge-slight-left, arrive |
+ | waypoints | route | turns |
+ | a,e | abcde,abcde | depart,arrive |
+ | f,e | fgd,abcde,abcde | depart,merge slight left,arrive |
Scenario: On Ramp Left
Given the node map
@@ -127,9 +127,9 @@ Feature: Basic Roundabout
| fgd | motorway_link |
When I route I should get
- | waypoints | route | turns |
- | a,e | abcde, abcde | depart, arrive |
- | f,e | abcde, fgd, fgd | depart, merge-slight-right, arrive |
+ | waypoints | route | turns |
+ | a,e | abcde,abcde | depart,arrive |
+ | f,e | fgd,abcde,abcde | depart,merge slight right,arrive |
Scenario: Highway Fork
Given the node map
@@ -143,9 +143,9 @@ Feature: Basic Roundabout
| cfg | motorway |
When I route I should get
- | waypoints | route | turns |
- | a,e | abcde, abcde, abcde | depart, fork-left, arrive |
- | a,g | abcde, cfg, cfg | depart, fork-right, arrive |
+ | waypoints | route | turns |
+ | a,e | abcde,abcde,abcde | depart,fork slight left,arrive |
+ | a,g | abcde,cfg,cfg | depart,fork slight right,arrive |
Scenario: Fork After Ramp
Given the node map
@@ -160,9 +160,9 @@ Feature: Basic Roundabout
| cfg | motorway |
When I route I should get
- | waypoints | route | turns |
- | a,e | abc, cde, cde | depart, fork-left, arrive |
- | a,g | abc, cfg, cfg | depart, fork-right, arrive |
+ | waypoints | route | turns |
+ | a,e | abc,cde,cde | depart,fork slight left,arrive |
+ | a,g | abc,cfg,cfg | depart,fork slight right,arrive |
Scenario: On And Off Ramp Right
Given the node map
@@ -176,11 +176,11 @@ Feature: Basic Roundabout
| chi | motorway_link |
When I route I should get
- | waypoints | route | turns |
- | a,e | abcde, abcde | depart, arrive |
- | f,e | fgc, abcde, abcde | depart, merge-slight-left, arrive |
- | a,i | abcde, chi, chi | depart, ramp-slight-right, arrive |
- | f,i | fgc, chi, chi | depart, turn-slight-right, arrive |
+ | waypoints | route | turns |
+ | a,e | abcde,abcde | depart,arrive |
+ | f,e | fgc,abcde,abcde | depart,merge slight left,arrive |
+ | a,i | abcde,chi,chi | depart,ramp slight right,arrive |
+ | f,i | fgc,chi,chi | depart,ramp right,arrive |
Scenario: On And Off Ramp Left
Given the node map
@@ -194,9 +194,25 @@ Feature: Basic Roundabout
| chi | motorway_link |
When I route I should get
- | waypoints | route | turns |
- | a,e | abcde, abcde | depart, arrive |
- | f,e | fgc, abcde, abcde | depart, merge-slight-right, arrive |
- | a,i | abcde, chi, chi | depart, ramp-slight-left, arrive |
- | f,i | fgc, chi, chi | depart, turn-slight-left, arrive |
+ | waypoints | route | turns |
+ | a,e | abcde,abcde | depart,arrive |
+ | f,e | fgc,abcde,abcde | depart,merge slight right,arrive |
+ | a,i | abcde,chi,chi | depart,ramp slight left,arrive |
+ | f,i | fgc,chi,chi | depart,ramp left,arrive |
+
+ Scenario: Merging Motorways
+ Given the node map
+ | e | | |
+ | a | b | c |
+ | d | | |
+ And the ways
+ | nodes | highway |
+ | abc | motorway |
+ | db | motorway |
+ | eb | motorway |
+
+ When I route I should get
+ | waypoints | route | turns |
+ | d,c | db,abc,abc | depart,merge slight left,arrive |
+ | e,c | eb,abc,abc | depart,merge slight right,arrive |
diff --git a/features/guidance/new-name.feature b/features/guidance/new-name.feature
new file mode 100644
index 0000000..1fdf1ce
--- /dev/null
+++ b/features/guidance/new-name.feature
@@ -0,0 +1,135 @@
+ at routing @guidance
+Feature: New-Name Instructions
+
+ Background:
+ Given the profile "car"
+ Given a grid size of 10 meters
+
+ Scenario: Undisturbed name Change
+ Given the node map
+ | a | | b | | c |
+
+ And the ways
+ | nodes |
+ | ab |
+ | bc |
+
+ When I route I should get
+ | waypoints | route | turns |
+ | a,c | ab,bc,bc | depart,new name straight,arrive |
+
+
+ Scenario: Undisturbed Name Change with unannounced Turn Right
+ Given the node map
+ | a | | b | | |
+ | | | | | c |
+
+ And the ways
+ | nodes |
+ | ab |
+ | bc |
+
+ When I route I should get
+ | waypoints | route | turns |
+ | a,c | ab,bc,bc | depart,new name slight right,arrive |
+
+ Scenario: Undisturbed Name Change with unannounced Turn Left
+ Given the node map
+ | | | | | c |
+ | a | | b | | |
+
+ And the ways
+ | nodes |
+ | ab |
+ | bc |
+
+ When I route I should get
+ | waypoints | route | turns |
+ | a,c | ab,bc,bc | depart,new name slight left,arrive |
+
+ Scenario: Disturbed Name Change with Turn
+ Given the node map
+ | a | | b | | |
+ | | d | | | c |
+
+ And the ways
+ | nodes |
+ | ab |
+ | bc |
+ | db |
+
+ When I route I should get
+ | waypoints | route | turns |
+ | a,c | ab,bc,bc | depart,new name slight right,arrive |
+
+ Scenario: Undisturbed Name Change with announced Turn Left
+ Given the node map
+ | | | c |
+ | a | | b |
+
+ And the ways
+ | nodes |
+ | ab |
+ | bc |
+
+ When I route I should get
+ | waypoints | route | turns |
+ | a,c | ab,bc,bc | depart,new name left,arrive |
+
+ Scenario: Undisturbed Name Change with announced Turn Sharp Left
+ Given the node map
+ | c | | |
+ | a | | b |
+
+ And the ways
+ | nodes |
+ | ab |
+ | bc |
+
+ When I route I should get
+ | waypoints | route | turns |
+ | a,c | ab,bc,bc | depart,new name sharp left,arrive |
+
+ Scenario: Undisturbed Name Change with announced Turn Right
+ Given the node map
+ | a | | b |
+ | | | c |
+
+ And the ways
+ | nodes |
+ | ab |
+ | bc |
+
+ When I route I should get
+ | waypoints | route | turns |
+ | a,c | ab,bc,bc | depart,new name right,arrive |
+
+ Scenario: Undisturbed Name Change with announced Turn Sharp Right
+ Given the node map
+ | a | | b |
+ | c | | |
+
+ And the ways
+ | nodes |
+ | ab |
+ | bc |
+
+ When I route I should get
+ | waypoints | route | turns |
+ | a,c | ab,bc,bc | depart,new name sharp right,arrive |
+
+
+ Scenario: Disturbed Name Change with minor road class
+ Given the node map
+ | a | | b | | d |
+ | | | | | c |
+
+ And the ways
+ | nodes | highway |
+ | ab | residential |
+ | bc | residential |
+ | bd | service |
+
+ When I route I should get
+ | waypoints | route | turns |
+ | a,c | ab,bc,bc | depart,new name slight right,arrive |
diff --git a/features/guidance/ramp.feature b/features/guidance/ramp.feature
new file mode 100644
index 0000000..3c3ce39
--- /dev/null
+++ b/features/guidance/ramp.feature
@@ -0,0 +1,229 @@
+ at routing @guidance
+Feature: Ramp Guidance
+
+ Background:
+ Given the profile "car"
+ Given a grid size of 10 meters
+
+ Scenario: Ramp On Through Street Right
+ Given the node map
+ | a | b | c |
+ | | d | |
+
+ And the ways
+ | nodes | highway |
+ | abc | tertiary |
+ | bd | motorway_link |
+
+ When I route I should get
+ | waypoints | route | turns |
+ | a,d | abc,bd,bd | depart,ramp right,arrive |
+
+ Scenario: Ramp On Through Street Left
+ Given the node map
+ | | d | |
+ | a | b | c |
+
+ And the ways
+ | nodes | highway |
+ | abc | tertiary |
+ | bd | motorway_link |
+
+ When I route I should get
+ | waypoints | route | turns |
+ | a,d | abc,bd,bd | depart,ramp left,arrive |
+
+ Scenario: Ramp On Through Street Left and Right
+ Given the node map
+ | | e | |
+ | a | b | c |
+ | | d | |
+
+ And the ways
+ | nodes | highway |
+ | be | motorway_link |
+ | abc | tertiary |
+ | bd | motorway_link |
+
+ When I route I should get
+ | waypoints | route | turns |
+ | a,d | abc,bd,bd | depart,ramp right,arrive |
+ | a,e | abc,be,be | depart,ramp left,arrive |
+
+ Scenario: Ramp On Three Way Intersection Right
+ Given the node map
+ | a | b | c |
+ | | d | |
+
+ And the ways
+ | nodes | highway |
+ | ab | tertiary |
+ | bc | tertiary |
+ | bd | motorway_link |
+
+ When I route I should get
+ | waypoints | route | turns |
+ | a,d | ab,bd,bd | depart,ramp right,arrive |
+
+ Scenario: Ramp On Three Way Intersection Right
+ Given the node map
+ | | | c |
+ | a | b | |
+ | | d | |
+
+ And the ways
+ | nodes | highway |
+ | ab | tertiary |
+ | bc | tertiary |
+ | bd | motorway_link |
+
+ When I route I should get
+ | waypoints | route | turns |
+ | a,d | ab,bd,bd | depart,ramp right,arrive |
+
+ Scenario: Ramp Off Though Street
+ Given the node map
+ | | | c |
+ | a | b | |
+ | | d | |
+
+ And the ways
+ | nodes | highway |
+ | abc | tertiary |
+ | bd | motorway_link |
+
+ When I route I should get
+ | waypoints | route | turns |
+ | a,d | abc,bd,bd | depart,ramp right,arrive |
+ | a,c | abc,abc | depart,arrive |
+
+ Scenario: Straight Ramp Off Turning Though Street
+ Given the node map
+ | | | c |
+ | a | b | d |
+
+ And the ways
+ | nodes | highway |
+ | abc | tertiary |
+ | bd | motorway_link |
+
+ When I route I should get
+ | waypoints | route | turns |
+ | a,d | abc,bd,bd | depart,ramp straight,arrive |
+ | a,c | abc,abc,abc | depart,continue left,arrive |
+
+ Scenario: Fork Ramp Off Turning Though Street
+ Given the node map
+ | | | c |
+ | a | b | |
+ | | | d |
+
+ And the ways
+ | nodes | highway |
+ | abc | tertiary |
+ | bd | motorway_link |
+
+ When I route I should get
+ | waypoints | route | turns |
+ | a,d | abc,bd,bd | depart,ramp right,arrive |
+ | a,c | abc,abc,abc | depart,continue left,arrive |
+
+ Scenario: Fork Ramp
+ Given the node map
+ | | | c |
+ | a | b | |
+ | | | d |
+
+ And the ways
+ | nodes | highway |
+ | ab | tertiary |
+ | bc | tertiary |
+ | bd | motorway_link |
+
+ When I route I should get
+ | waypoints | route | turns |
+ | a,d | ab,bd,bd | depart,ramp right,arrive |
+ | a,c | ab,bc,bc | depart,turn left,arrive |
+
+ Scenario: Fork Slight Ramp
+ Given the node map
+ | | | | c |
+ | a | b | | |
+ | | | | d |
+
+ And the ways
+ | nodes | highway |
+ | ab | tertiary |
+ | bc | tertiary |
+ | bd | motorway_link |
+
+ When I route I should get
+ | waypoints | route | turns |
+ | a,d | ab,bd,bd | depart,ramp slight right,arrive |
+ | a,c | ab,bc,bc | depart,turn slight left,arrive |
+
+ Scenario: Fork Slight Ramp on Through Street
+ Given the node map
+ | | | | c |
+ | a | b | | |
+ | | | | d |
+
+ And the ways
+ | nodes | highway |
+ | abc | tertiary |
+ | bd | motorway_link |
+
+ When I route I should get
+ | waypoints | route | turns |
+ | a,d | abc,bd,bd | depart,ramp slight right,arrive |
+ | a,c | abc,abc,abc | depart,continue slight left,arrive |
+
+ Scenario: Fork Slight Ramp on Obvious Through Street
+ Given the node map
+ | | | | c |
+ | a | b | | |
+ | | | | d |
+
+ And the ways
+ | nodes | highway |
+ | abc | primary |
+ | bd | motorway_link |
+
+ When I route I should get
+ | waypoints | route | turns |
+ | a,d | abc,bd,bd | depart,ramp slight right,arrive |
+ | a,c | abc,abc | depart,arrive |
+
+ Scenario: Two Ramps Joining into common Motorway
+ Given the node map
+ | a | | | |
+ | | | c | d |
+ | b | | | |
+
+ And the ways
+ | nodes | highway |
+ | ac | motorway_link |
+ | bc | motorway_link |
+ | cd | motorway |
+
+ When I route I should get
+ | waypoints | route | turns |
+ | a,d | ac,cd,cd | depart,new name slight left,arrive |
+ | b,d | bc,cd,cd | depart,new name slight right,arrive |
+
+ Scenario: Two Ramps Joining into common Motorway Unnamed
+ Given the node map
+ | a | | | |
+ | | | c | d |
+ | b | | | |
+
+ And the ways
+ | nodes | highway | name |
+ | ac | motorway_link | |
+ | bc | motorway_link | |
+ | cd | motorway | |
+
+ When I route I should get
+ | waypoints | route | turns |
+ | a,d | , | depart,arrive |
+ | b,d | , | depart,arrive |
diff --git a/features/guidance/rotary-bike.feature b/features/guidance/rotary-bike.feature
new file mode 100644
index 0000000..512b815
--- /dev/null
+++ b/features/guidance/rotary-bike.feature
@@ -0,0 +1,167 @@
+ at routing @guidance
+Feature: Rotary
+
+ Background:
+ Given the profile "bicycle"
+ Given a grid size of 30 meters
+
+ Scenario: Enter and Exit
+ Given the node map
+ | | | a | | |
+ | | | b | | |
+ | h | g | | c | d |
+ | | | e | | |
+ | | | f | | |
+
+ And the ways
+ | nodes | junction |
+ | ab | |
+ | cd | |
+ | ef | |
+ | gh | |
+ | bgecb | roundabout |
+
+ When I route I should get
+ | waypoints | route | turns |
+ | a,d | ab,cd,cd | depart,bgecb-exit-3,arrive |
+ | a,f | ab,ef,ef | depart,bgecb-exit-2,arrive |
+ | a,h | ab,gh,gh | depart,bgecb-exit-1,arrive |
+ | d,f | cd,ef,ef | depart,bgecb-exit-3,arrive |
+ | d,h | cd,gh,gh | depart,bgecb-exit-2,arrive |
+ | d,a | cd,ab,ab | depart,bgecb-exit-1,arrive |
+ | f,h | ef,gh,gh | depart,bgecb-exit-3,arrive |
+ | f,a | ef,ab,ab | depart,bgecb-exit-2,arrive |
+ | f,d | ef,cd,cd | depart,bgecb-exit-1,arrive |
+ | h,a | gh,ab,ab | depart,bgecb-exit-3,arrive |
+ | h,d | gh,cd,cd | depart,bgecb-exit-2,arrive |
+ | h,f | gh,ef,ef | depart,bgecb-exit-1,arrive |
+
+ Scenario: Only Enter
+ Given the node map
+ | | | a | | |
+ | | | b | | |
+ | d | c | | g | h |
+ | | | e | | |
+ | | | f | | |
+
+ And the ways
+ | nodes | junction |
+ | ab | |
+ | cd | |
+ | ef | |
+ | gh | |
+ | bcegb | roundabout |
+
+ When I route I should get
+ | waypoints | route | turns |
+ | a,c | ab,bcegb,bcegb | depart,bcegb-exit-undefined,arrive |
+ | a,e | ab,bcegb,bcegb | depart,bcegb-exit-undefined,arrive |
+ | a,g | ab,bcegb,bcegb | depart,bcegb-exit-undefined,arrive |
+ | d,e | cd,bcegb,bcegb | depart,bcegb-exit-undefined,arrive |
+ | d,g | cd,bcegb,bcegb | depart,bcegb-exit-undefined,arrive |
+ | d,b | cd,bcegb,bcegb | depart,bcegb-exit-undefined,arrive |
+ | f,g | ef,bcegb,bcegb | depart,bcegb-exit-undefined,arrive |
+ | f,b | ef,bcegb,bcegb | depart,bcegb-exit-undefined,arrive |
+ | f,c | ef,bcegb,bcegb | depart,bcegb-exit-undefined,arrive |
+ | h,b | gh,bcegb,bcegb | depart,bcegb-exit-undefined,arrive |
+ | h,c | gh,bcegb,bcegb | depart,bcegb-exit-undefined,arrive |
+ | h,e | gh,bcegb,bcegb | depart,bcegb-exit-undefined,arrive |
+
+ Scenario: Only Exit
+ Given the node map
+ | | | a | | |
+ | | | b | | |
+ | d | c | | g | h |
+ | | | e | | |
+ | | | f | | |
+
+ And the ways
+ | nodes | junction |
+ | ab | |
+ | cd | |
+ | ef | |
+ | gh | |
+ | bcegb | roundabout |
+
+ When I route I should get
+ | waypoints | route | turns |
+ | b,d | bcegb,cd,cd | depart,bcegb-exit-1,arrive |
+ | b,f | bcegb,ef,ef | depart,bcegb-exit-2,arrive |
+ | b,h | bcegb,gh,gh | depart,bcegb-exit-3,arrive |
+ | c,f | bcegb,ef,ef | depart,bcegb-exit-1,arrive |
+ | c,h | bcegb,gh,gh | depart,bcegb-exit-2,arrive |
+ | c,a | bcegb,ab,ab | depart,bcegb-exit-3,arrive |
+ | e,h | bcegb,gh,gh | depart,bcegb-exit-1,arrive |
+ | e,a | bcegb,ab,ab | depart,bcegb-exit-2,arrive |
+ | e,d | bcegb,cd,cd | depart,bcegb-exit-3,arrive |
+ | g,a | bcegb,ab,ab | depart,bcegb-exit-1,arrive |
+ | g,d | bcegb,cd,cd | depart,bcegb-exit-2,arrive |
+ | g,f | bcegb,ef,ef | depart,bcegb-exit-3,arrive |
+ #phantom node snapping can result in a full round-trip here, therefore we cannot test b->a and the other direct exits
+
+ Scenario: Drive Around
+ Given the node map
+ | | | a | | |
+ | | | b | | |
+ | d | c | | g | h |
+ | | | e | | |
+ | | | f | | |
+
+ And the ways
+ | nodes | junction |
+ | ab | |
+ | cd | |
+ | ef | |
+ | gh | |
+ | bcegb | roundabout |
+
+ When I route I should get
+ | waypoints | route | turns |
+ | b,c | bcegb,bcegb | depart,arrive |
+ | b,e | bcegb,bcegb | depart,arrive |
+ | b,g | bcegb,bcegb | depart,arrive |
+ | c,e | bcegb,bcegb | depart,arrive |
+ | c,g | bcegb,bcegb | depart,arrive |
+ | c,b | bcegb,bcegb | depart,arrive |
+ | e,g | bcegb,bcegb | depart,arrive |
+ | e,b | bcegb,bcegb | depart,arrive |
+ | e,c | bcegb,bcegb | depart,arrive |
+ | g,b | bcegb,bcegb | depart,arrive |
+ | g,c | bcegb,bcegb | depart,arrive |
+ | g,e | bcegb,bcegb | depart,arrive |
+
+ #needs to be adjusted when name-discovery works for entrys
+ Scenario: Mixed Entry and Exit
+ Given the node map
+ | | c | | a | |
+ | j | | b | | f |
+ | | k | | e | |
+ | l | | h | | d |
+ | | g | | i | |
+
+ And the ways
+ | nodes | junction | oneway |
+ | abc | | yes |
+ | def | | yes |
+ | ghi | | yes |
+ | jkl | | yes |
+ | bkheb | roundabout | yes |
+
+ When I route I should get
+ | waypoints | route | turns |
+ | a,c | abc,abc,abc | depart,rotary-exit-1,arrive |
+ | a,l | abc,jkl,jkl | depart,bkheb-exit-2,arrive |
+ | a,i | abc,ghi,ghi | depart,bkheb-exit-3,arrive |
+ | a,f | abc,def,def | depart,bkheb-exit-4,arrive |
+ | d,f | def,def,def | depart,rotary-exit-1,arrive |
+ | d,c | def,abc,abc | depart,bkheb-exit-2,arrive |
+ | d,l | def,jkl,jkl | depart,bkheb-exit-3,arrive |
+ | d,i | def,ghi,ghi | depart,bkheb-exit-4,arrive |
+ | g,i | ghi,ghi,ghi | depart,rotary-exit-1,arrive |
+ | g,f | ghi,def,def | depart,bkheb-exit-2,arrive |
+ | g,c | ghi,abc,abc | depart,bkheb-exit-3,arrive |
+ | g,l | ghi,jkl,jkl | depart,bkheb-exit-4,arrive |
+ | j,l | jkl,jkl,jkl | depart,rotary-exit-1,arrive |
+ | j,i | jkl,ghi,ghi | depart,bkheb-exit-2,arrive |
+ | j,f | jkl,def,def | depart,bkheb-exit-3,arrive |
+ | j,c | jkl,abc,abc | depart,bkheb-exit-4,arrive |
diff --git a/features/guidance/rotary.feature b/features/guidance/rotary.feature
new file mode 100644
index 0000000..e1b14d3
--- /dev/null
+++ b/features/guidance/rotary.feature
@@ -0,0 +1,262 @@
+ at routing @guidance
+Feature: Rotary
+
+ Background:
+ Given the profile "car"
+ Given a grid size of 30 meters
+
+ Scenario: Enter and Exit
+ Given the node map
+ | | | a | | |
+ | | | b | | |
+ | h | g | | c | d |
+ | | | e | | |
+ | | | f | | |
+
+ And the ways
+ | nodes | junction |
+ | ab | |
+ | cd | |
+ | ef | |
+ | gh | |
+ | bgecb | roundabout |
+
+ When I route I should get
+ | waypoints | route | turns |
+ | a,d | ab,cd,cd | depart,bgecb-exit-3,arrive |
+ | a,f | ab,ef,ef | depart,bgecb-exit-2,arrive |
+ | a,h | ab,gh,gh | depart,bgecb-exit-1,arrive |
+ | d,f | cd,ef,ef | depart,bgecb-exit-3,arrive |
+ | d,h | cd,gh,gh | depart,bgecb-exit-2,arrive |
+ | d,a | cd,ab,ab | depart,bgecb-exit-1,arrive |
+ | f,h | ef,gh,gh | depart,bgecb-exit-3,arrive |
+ | f,a | ef,ab,ab | depart,bgecb-exit-2,arrive |
+ | f,d | ef,cd,cd | depart,bgecb-exit-1,arrive |
+ | h,a | gh,ab,ab | depart,bgecb-exit-3,arrive |
+ | h,d | gh,cd,cd | depart,bgecb-exit-2,arrive |
+ | h,f | gh,ef,ef | depart,bgecb-exit-1,arrive |
+
+ Scenario: Only Enter
+ Given the node map
+ | | | a | | |
+ | | | b | | |
+ | d | c | | g | h |
+ | | | e | | |
+ | | | f | | |
+
+ And the ways
+ | nodes | junction |
+ | ab | |
+ | cd | |
+ | ef | |
+ | gh | |
+ | bcegb | roundabout |
+
+ When I route I should get
+ | waypoints | route | turns |
+ | a,c | ab,bcegb,bcegb | depart,bcegb-exit-undefined,arrive |
+ | a,e | ab,bcegb,bcegb | depart,bcegb-exit-undefined,arrive |
+ | a,g | ab,bcegb,bcegb | depart,bcegb-exit-undefined,arrive |
+ | d,e | cd,bcegb,bcegb | depart,bcegb-exit-undefined,arrive |
+ | d,g | cd,bcegb,bcegb | depart,bcegb-exit-undefined,arrive |
+ | d,b | cd,bcegb,bcegb | depart,bcegb-exit-undefined,arrive |
+ | f,g | ef,bcegb,bcegb | depart,bcegb-exit-undefined,arrive |
+ | f,b | ef,bcegb,bcegb | depart,bcegb-exit-undefined,arrive |
+ | f,c | ef,bcegb,bcegb | depart,bcegb-exit-undefined,arrive |
+ | h,b | gh,bcegb,bcegb | depart,bcegb-exit-undefined,arrive |
+ | h,c | gh,bcegb,bcegb | depart,bcegb-exit-undefined,arrive |
+ | h,e | gh,bcegb,bcegb | depart,bcegb-exit-undefined,arrive |
+
+ Scenario: Only Exit
+ Given the node map
+ | | | a | | |
+ | | | b | | |
+ | d | c | | g | h |
+ | | | e | | |
+ | | | f | | |
+
+ And the ways
+ | nodes | junction |
+ | ab | |
+ | cd | |
+ | ef | |
+ | gh | |
+ | bcegb | roundabout |
+
+ When I route I should get
+ | waypoints | route | turns |
+ | b,d | bcegb,cd,cd | depart,bcegb-exit-1,arrive |
+ | b,f | bcegb,ef,ef | depart,bcegb-exit-2,arrive |
+ | b,h | bcegb,gh,gh | depart,bcegb-exit-3,arrive |
+ | c,f | bcegb,ef,ef | depart,bcegb-exit-1,arrive |
+ | c,h | bcegb,gh,gh | depart,bcegb-exit-2,arrive |
+ | c,a | bcegb,ab,ab | depart,bcegb-exit-3,arrive |
+ | e,h | bcegb,gh,gh | depart,bcegb-exit-1,arrive |
+ | e,a | bcegb,ab,ab | depart,bcegb-exit-2,arrive |
+ | e,d | bcegb,cd,cd | depart,bcegb-exit-3,arrive |
+ | g,a | bcegb,ab,ab | depart,bcegb-exit-1,arrive |
+ | g,d | bcegb,cd,cd | depart,bcegb-exit-2,arrive |
+ | g,f | bcegb,ef,ef | depart,bcegb-exit-3,arrive |
+ #phantom node snapping can result in a full round-trip here, therefore we cannot test b->a and the other direct exits
+
+ Scenario: Drive Around
+ Given the node map
+ | | | a | | |
+ | | | b | | |
+ | d | c | | g | h |
+ | | | e | | |
+ | | | f | | |
+
+ And the ways
+ | nodes | junction |
+ | ab | |
+ | cd | |
+ | ef | |
+ | gh | |
+ | bcegb | roundabout |
+
+ When I route I should get
+ | waypoints | route | turns |
+ | b,c | bcegb,bcegb | depart,arrive |
+ | b,e | bcegb,bcegb | depart,arrive |
+ | b,g | bcegb,bcegb | depart,arrive |
+ | c,e | bcegb,bcegb | depart,arrive |
+ | c,g | bcegb,bcegb | depart,arrive |
+ | c,b | bcegb,bcegb | depart,arrive |
+ | e,g | bcegb,bcegb | depart,arrive |
+ | e,b | bcegb,bcegb | depart,arrive |
+ | e,c | bcegb,bcegb | depart,arrive |
+ | g,b | bcegb,bcegb | depart,arrive |
+ | g,c | bcegb,bcegb | depart,arrive |
+ | g,e | bcegb,bcegb | depart,arrive |
+
+ #needs to be adjusted when name-discovery works for entrys
+ Scenario: Mixed Entry and Exit
+ Given the node map
+ | | c | | a | |
+ | j | | b | | f |
+ | | k | | e | |
+ | l | | h | | d |
+ | | g | | i | |
+
+ And the ways
+ | nodes | junction | oneway |
+ | abc | | yes |
+ | def | | yes |
+ | ghi | | yes |
+ | jkl | | yes |
+ | bkheb | roundabout | yes |
+
+ When I route I should get
+ | waypoints | route | turns |
+ | a,c | abc,abc,abc | depart,rotary-exit-1,arrive |
+ | a,l | abc,jkl,jkl | depart,bkheb-exit-2,arrive |
+ | a,i | abc,ghi,ghi | depart,bkheb-exit-3,arrive |
+ | a,f | abc,def,def | depart,bkheb-exit-4,arrive |
+ | d,f | def,def,def | depart,rotary-exit-1,arrive |
+ | d,c | def,abc,abc | depart,bkheb-exit-2,arrive |
+ | d,l | def,jkl,jkl | depart,bkheb-exit-3,arrive |
+ | d,i | def,ghi,ghi | depart,bkheb-exit-4,arrive |
+ | g,i | ghi,ghi,ghi | depart,rotary-exit-1,arrive |
+ | g,f | ghi,def,def | depart,bkheb-exit-2,arrive |
+ | g,c | ghi,abc,abc | depart,bkheb-exit-3,arrive |
+ | g,l | ghi,jkl,jkl | depart,bkheb-exit-4,arrive |
+ | j,l | jkl,jkl,jkl | depart,rotary-exit-1,arrive |
+ | j,i | jkl,ghi,ghi | depart,bkheb-exit-2,arrive |
+ | j,f | jkl,def,def | depart,bkheb-exit-3,arrive |
+ | j,c | jkl,abc,abc | depart,bkheb-exit-4,arrive |
+
+ Scenario: Collinear in X,Y
+ Given the node map
+ | a | | |
+ | b | | |
+ | c | d | f |
+ | e | | |
+
+ And the ways
+ | nodes | junction |
+ | ab | |
+ | bcdb | roundabout |
+ | ce | |
+ | df | |
+
+ When I route I should get
+ | waypoints | route | turns |
+ | a,e | ab,ce,ce | depart,bcdb-exit-1,arrive |
+ | a,f | ab,df,df | depart,bcdb-exit-2,arrive |
+
+ Scenario: Collinear in X,Y
+ Given the node map
+ | a | | |
+ | d | | |
+ | b | c | f |
+ | e | | |
+
+ And the ways
+ | nodes | junction |
+ | ab | |
+ | bcdb | roundabout |
+ | ce | |
+ | df | |
+
+ When I route I should get
+ | waypoints | route | turns |
+ | a,e | ab,ce,ce | depart,bcdb-exit-1,arrive |
+ | a,f | ab,df,df | depart,bcdb-exit-2,arrive |
+
+ Scenario: Collinear in X,Y
+ Given the node map
+ | a | | |
+ | c | | |
+ | d | b | f |
+ | e | | |
+
+ And the ways
+ | nodes | junction |
+ | ab | |
+ | bcdb | roundabout |
+ | ce | |
+ | df | |
+
+ When I route I should get
+ | waypoints | route | turns |
+ | a,e | ab,ce,ce | depart,bcdb-exit-1,arrive |
+ | a,f | ab,df,df | depart,bcdb-exit-2,arrive |
+
+ Scenario: Collinear in X,Y
+ Given the node map
+ | f | | |
+ | d | c | e |
+ | | b | |
+ | | a | |
+
+ And the ways
+ | nodes | junction |
+ | ab | |
+ | bcdb | roundabout |
+ | ce | |
+ | df | |
+
+ When I route I should get
+ | waypoints | route | turns |
+ | a,e | ab,ce,ce | depart,bcdb-exit-1,arrive |
+ | a,f | ab,df,df | depart,bcdb-exit-2,arrive |
+
+ Scenario: Collinear in X,Y
+ Given the node map
+ | f | | |
+ | d | c | e |
+ | b | | |
+ | a | | |
+
+ And the ways
+ | nodes | junction |
+ | ab | |
+ | bcdb | roundabout |
+ | ce | |
+ | df | |
+
+ When I route I should get
+ | waypoints | route | turns |
+ | a,e | ab,ce,ce | depart,bcdb-exit-1,arrive |
+ | a,f | ab,df,df | depart,bcdb-exit-2,arrive |
diff --git a/features/guidance/roundabout.feature b/features/guidance/roundabout-bike.feature
similarity index 64%
copy from features/guidance/roundabout.feature
copy to features/guidance/roundabout-bike.feature
index 21d6530..3652c15 100644
--- a/features/guidance/roundabout.feature
+++ b/features/guidance/roundabout-bike.feature
@@ -2,7 +2,7 @@
Feature: Basic Roundabout
Background:
- Given the profile "testbot"
+ Given the profile "bicycle"
Given a grid size of 10 meters
Scenario: Enter and Exit
@@ -19,28 +19,28 @@ Feature: Basic Roundabout
| cd | |
| ef | |
| gh | |
- | bcegb | roundabout |
+ | bgecb | roundabout |
When I route I should get
| waypoints | route | turns |
- | a,d | ab,cd,cd | depart,roundabout-exit-1,arrive |
+ | a,d | ab,cd,cd | depart,roundabout-exit-3,arrive |
| a,f | ab,ef,ef | depart,roundabout-exit-2,arrive |
- | a,h | ab,gh,gh | depart,roundabout-exit-3,arrive |
- | d,f | cd,ef,ef | depart,roundabout-exit-1,arrive |
+ | a,h | ab,gh,gh | depart,roundabout-exit-1,arrive |
+ | d,f | cd,ef,ef | depart,roundabout-exit-3,arrive |
| d,h | cd,gh,gh | depart,roundabout-exit-2,arrive |
- | d,a | cd,ab,ab | depart,roundabout-exit-3,arrive |
- | f,h | ef,gh,gh | depart,roundabout-exit-1,arrive |
+ | d,a | cd,ab,ab | depart,roundabout-exit-1,arrive |
+ | f,h | ef,gh,gh | depart,roundabout-exit-3,arrive |
| f,a | ef,ab,ab | depart,roundabout-exit-2,arrive |
- | f,d | ef,cd,cd | depart,roundabout-exit-3,arrive |
- | h,a | gh,ab,ab | depart,roundabout-exit-1,arrive |
+ | f,d | ef,cd,cd | depart,roundabout-exit-1,arrive |
+ | h,a | gh,ab,ab | depart,roundabout-exit-3,arrive |
| h,d | gh,cd,cd | depart,roundabout-exit-2,arrive |
- | h,f | gh,ef,ef | depart,roundabout-exit-3,arrive |
+ | h,f | gh,ef,ef | depart,roundabout-exit-1,arrive |
Scenario: Only Enter
Given the node map
| | | a | | |
| | | b | | |
- | h | g | | c | d |
+ | d | c | | g | h |
| | | e | | |
| | | f | | |
@@ -53,29 +53,25 @@ Feature: Basic Roundabout
| bcegb | roundabout |
When I route I should get
- | waypoints | route | turns |
- | a,b | ab,ab | depart,arrive |
- | a,c | ab,bcegb | depart,roundabout-enter,arrive |
- | a,e | ab,bcegb | depart,roundabout-enter,arrive |
- | a,g | ab,bcegb | depart,roundabout-enter,arrive |
- | d,c | cd,cd | depart,arrive |
- | d,e | cd,bcegb | depart,roundabout-enter,arrive |
- | d,g | cd,bcegb | depart,roundabout-enter,arrive |
- | d,b | cd,bcegb | depart,roundabout-enter,arrive |
- | f,e | ef,ef | depart,arrive |
- | f,g | ef,bcegb | depart,roundabout-enter,arrive |
- | f,b | ef,bcegb | depart,roundabout-enter,arrive |
- | f,c | ef,bcegb | depart,roundabout-enter,arrive |
- | h,g | gh,gh | depart,arrive |
- | h,b | gh,bcegb | depart,roundabout-enter,arrive |
- | h,c | gh,bcegb | depart,roundabout-enter,arrive |
- | h,e | gh,bcegb | depart,roundabout-enter,arrive |
+ | waypoints | route | turns |
+ | a,c | ab,bcegb,bcegb | depart,roundabout-exit-undefined,arrive |
+ | a,e | ab,bcegb,bcegb | depart,roundabout-exit-undefined,arrive |
+ | a,g | ab,bcegb,bcegb | depart,roundabout-exit-undefined,arrive |
+ | d,e | cd,bcegb,bcegb | depart,roundabout-exit-undefined,arrive |
+ | d,g | cd,bcegb,bcegb | depart,roundabout-exit-undefined,arrive |
+ | d,b | cd,bcegb,bcegb | depart,roundabout-exit-undefined,arrive |
+ | f,g | ef,bcegb,bcegb | depart,roundabout-exit-undefined,arrive |
+ | f,b | ef,bcegb,bcegb | depart,roundabout-exit-undefined,arrive |
+ | f,c | ef,bcegb,bcegb | depart,roundabout-exit-undefined,arrive |
+ | h,b | gh,bcegb,bcegb | depart,roundabout-exit-undefined,arrive |
+ | h,c | gh,bcegb,bcegb | depart,roundabout-exit-undefined,arrive |
+ | h,e | gh,bcegb,bcegb | depart,roundabout-exit-undefined,arrive |
Scenario: Only Exit
Given the node map
| | | a | | |
| | | b | | |
- | h | g | | c | d |
+ | d | c | | g | h |
| | | e | | |
| | | f | | |
@@ -89,28 +85,25 @@ Feature: Basic Roundabout
When I route I should get
| waypoints | route | turns |
- | b,a | ab,ab | depart,arrive |
| b,d | bcegb,cd,cd | depart,roundabout-exit-1,arrive |
| b,f | bcegb,ef,ef | depart,roundabout-exit-2,arrive |
| b,h | bcegb,gh,gh | depart,roundabout-exit-3,arrive |
- | c,d | cd,cd | depart,arrive |
| c,f | bcegb,ef,ef | depart,roundabout-exit-1,arrive |
| c,h | bcegb,gh,gh | depart,roundabout-exit-2,arrive |
| c,a | bcegb,ab,ab | depart,roundabout-exit-3,arrive |
- | e,f | ef,ef | depart,arrive |
| e,h | bcegb,gh,gh | depart,roundabout-exit-1,arrive |
| e,a | bcegb,ab,ab | depart,roundabout-exit-2,arrive |
| e,d | bcegb,cd,cd | depart,roundabout-exit-3,arrive |
- | g,h | gh,gh | depart,arrive |
| g,a | bcegb,ab,ab | depart,roundabout-exit-1,arrive |
| g,d | bcegb,cd,cd | depart,roundabout-exit-2,arrive |
| g,f | bcegb,ef,ef | depart,roundabout-exit-3,arrive |
+ #phantom node snapping can result in a full round-trip here, therefore we cannot test b->a and the other direct exits
Scenario: Drive Around
Given the node map
| | | a | | |
| | | b | | |
- | h | g | | c | d |
+ | d | c | | g | h |
| | | e | | |
| | | f | | |
@@ -139,11 +132,11 @@ Feature: Basic Roundabout
Scenario: Mixed Entry and Exit
Given the node map
- | | a | | c | |
- | l | | b | | d |
+ | | c | | a | |
+ | j | | b | | f |
| | k | | e | |
- | j | | h | | f |
- | | i | | g | |
+ | l | | h | | d |
+ | | g | | i | |
And the ways
| nodes | junction | oneway |
@@ -151,23 +144,23 @@ Feature: Basic Roundabout
| def | | yes |
| ghi | | yes |
| jkl | | yes |
- | behkb | roundabout | yes |
+ | bkheb | roundabout | yes |
When I route I should get
| waypoints | route | turns |
| a,c | abc,abc,abc | depart,roundabout-exit-1,arrive |
- | a,f | abc,def,def | depart,roundabout-exit-2,arrive |
+ | a,l | abc,jkl,jkl | depart,roundabout-exit-2,arrive |
| a,i | abc,ghi,ghi | depart,roundabout-exit-3,arrive |
- | a,l | abc,jkl,jkl | depart,roundabout-exit-4,arrive |
+ | a,f | abc,def,def | depart,roundabout-exit-4,arrive |
| d,f | def,def,def | depart,roundabout-exit-1,arrive |
- | d,i | def,ghi,ghi | depart,roundabout-exit-2,arrive |
+ | d,c | def,abc,abc | depart,roundabout-exit-2,arrive |
| d,l | def,jkl,jkl | depart,roundabout-exit-3,arrive |
- | d,c | def,abc,abc | depart,roundabout-exit-4,arrive |
+ | d,i | def,ghi,ghi | depart,roundabout-exit-4,arrive |
| g,i | ghi,ghi,ghi | depart,roundabout-exit-1,arrive |
- | g,l | ghi,jkl,jkl | depart,roundabout-exit-2,arrive |
+ | g,f | ghi,def,def | depart,roundabout-exit-2,arrive |
| g,c | ghi,abc,abc | depart,roundabout-exit-3,arrive |
- | g,f | ghi,edf,edf | depart,roundabout-exit-4,arrive |
+ | g,l | ghi,jkl,jkl | depart,roundabout-exit-4,arrive |
| j,l | jkl,jkl,jkl | depart,roundabout-exit-1,arrive |
- | j,c | jkl,abc,abc | depart,roundabout-exit-2,arrive |
+ | j,i | jkl,ghi,ghi | depart,roundabout-exit-2,arrive |
| j,f | jkl,def,def | depart,roundabout-exit-3,arrive |
- | j,i | jkl,ghi,ghi | depart,roundabout-exit-4,arrive |
+ | j,c | jkl,abc,abc | depart,roundabout-exit-4,arrive |
diff --git a/features/guidance/roundabout.feature b/features/guidance/roundabout.feature
index 21d6530..d03737c 100644
--- a/features/guidance/roundabout.feature
+++ b/features/guidance/roundabout.feature
@@ -2,7 +2,7 @@
Feature: Basic Roundabout
Background:
- Given the profile "testbot"
+ Given the profile "car"
Given a grid size of 10 meters
Scenario: Enter and Exit
@@ -19,28 +19,28 @@ Feature: Basic Roundabout
| cd | |
| ef | |
| gh | |
- | bcegb | roundabout |
+ | bgecb | roundabout |
When I route I should get
| waypoints | route | turns |
- | a,d | ab,cd,cd | depart,roundabout-exit-1,arrive |
+ | a,d | ab,cd,cd | depart,roundabout-exit-3,arrive |
| a,f | ab,ef,ef | depart,roundabout-exit-2,arrive |
- | a,h | ab,gh,gh | depart,roundabout-exit-3,arrive |
- | d,f | cd,ef,ef | depart,roundabout-exit-1,arrive |
+ | a,h | ab,gh,gh | depart,roundabout-exit-1,arrive |
+ | d,f | cd,ef,ef | depart,roundabout-exit-3,arrive |
| d,h | cd,gh,gh | depart,roundabout-exit-2,arrive |
- | d,a | cd,ab,ab | depart,roundabout-exit-3,arrive |
- | f,h | ef,gh,gh | depart,roundabout-exit-1,arrive |
+ | d,a | cd,ab,ab | depart,roundabout-exit-1,arrive |
+ | f,h | ef,gh,gh | depart,roundabout-exit-3,arrive |
| f,a | ef,ab,ab | depart,roundabout-exit-2,arrive |
- | f,d | ef,cd,cd | depart,roundabout-exit-3,arrive |
- | h,a | gh,ab,ab | depart,roundabout-exit-1,arrive |
+ | f,d | ef,cd,cd | depart,roundabout-exit-1,arrive |
+ | h,a | gh,ab,ab | depart,roundabout-exit-3,arrive |
| h,d | gh,cd,cd | depart,roundabout-exit-2,arrive |
- | h,f | gh,ef,ef | depart,roundabout-exit-3,arrive |
+ | h,f | gh,ef,ef | depart,roundabout-exit-1,arrive |
Scenario: Only Enter
Given the node map
| | | a | | |
| | | b | | |
- | h | g | | c | d |
+ | d | c | | g | h |
| | | e | | |
| | | f | | |
@@ -53,29 +53,25 @@ Feature: Basic Roundabout
| bcegb | roundabout |
When I route I should get
- | waypoints | route | turns |
- | a,b | ab,ab | depart,arrive |
- | a,c | ab,bcegb | depart,roundabout-enter,arrive |
- | a,e | ab,bcegb | depart,roundabout-enter,arrive |
- | a,g | ab,bcegb | depart,roundabout-enter,arrive |
- | d,c | cd,cd | depart,arrive |
- | d,e | cd,bcegb | depart,roundabout-enter,arrive |
- | d,g | cd,bcegb | depart,roundabout-enter,arrive |
- | d,b | cd,bcegb | depart,roundabout-enter,arrive |
- | f,e | ef,ef | depart,arrive |
- | f,g | ef,bcegb | depart,roundabout-enter,arrive |
- | f,b | ef,bcegb | depart,roundabout-enter,arrive |
- | f,c | ef,bcegb | depart,roundabout-enter,arrive |
- | h,g | gh,gh | depart,arrive |
- | h,b | gh,bcegb | depart,roundabout-enter,arrive |
- | h,c | gh,bcegb | depart,roundabout-enter,arrive |
- | h,e | gh,bcegb | depart,roundabout-enter,arrive |
+ | waypoints | route | turns |
+ | a,c | ab,bcegb,bcegb | depart,roundabout-exit-undefined,arrive |
+ | a,e | ab,bcegb,bcegb | depart,roundabout-exit-undefined,arrive |
+ | a,g | ab,bcegb,bcegb | depart,roundabout-exit-undefined,arrive |
+ | d,e | cd,bcegb,bcegb | depart,roundabout-exit-undefined,arrive |
+ | d,g | cd,bcegb,bcegb | depart,roundabout-exit-undefined,arrive |
+ | d,b | cd,bcegb,bcegb | depart,roundabout-exit-undefined,arrive |
+ | f,g | ef,bcegb,bcegb | depart,roundabout-exit-undefined,arrive |
+ | f,b | ef,bcegb,bcegb | depart,roundabout-exit-undefined,arrive |
+ | f,c | ef,bcegb,bcegb | depart,roundabout-exit-undefined,arrive |
+ | h,b | gh,bcegb,bcegb | depart,roundabout-exit-undefined,arrive |
+ | h,c | gh,bcegb,bcegb | depart,roundabout-exit-undefined,arrive |
+ | h,e | gh,bcegb,bcegb | depart,roundabout-exit-undefined,arrive |
Scenario: Only Exit
Given the node map
| | | a | | |
| | | b | | |
- | h | g | | c | d |
+ | d | c | | g | h |
| | | e | | |
| | | f | | |
@@ -89,28 +85,25 @@ Feature: Basic Roundabout
When I route I should get
| waypoints | route | turns |
- | b,a | ab,ab | depart,arrive |
| b,d | bcegb,cd,cd | depart,roundabout-exit-1,arrive |
| b,f | bcegb,ef,ef | depart,roundabout-exit-2,arrive |
| b,h | bcegb,gh,gh | depart,roundabout-exit-3,arrive |
- | c,d | cd,cd | depart,arrive |
| c,f | bcegb,ef,ef | depart,roundabout-exit-1,arrive |
| c,h | bcegb,gh,gh | depart,roundabout-exit-2,arrive |
| c,a | bcegb,ab,ab | depart,roundabout-exit-3,arrive |
- | e,f | ef,ef | depart,arrive |
| e,h | bcegb,gh,gh | depart,roundabout-exit-1,arrive |
| e,a | bcegb,ab,ab | depart,roundabout-exit-2,arrive |
| e,d | bcegb,cd,cd | depart,roundabout-exit-3,arrive |
- | g,h | gh,gh | depart,arrive |
| g,a | bcegb,ab,ab | depart,roundabout-exit-1,arrive |
| g,d | bcegb,cd,cd | depart,roundabout-exit-2,arrive |
| g,f | bcegb,ef,ef | depart,roundabout-exit-3,arrive |
+ #phantom node snapping can result in a full round-trip here, therefore we cannot test b->a and the other direct exits
Scenario: Drive Around
Given the node map
| | | a | | |
| | | b | | |
- | h | g | | c | d |
+ | d | c | | g | h |
| | | e | | |
| | | f | | |
@@ -139,11 +132,11 @@ Feature: Basic Roundabout
Scenario: Mixed Entry and Exit
Given the node map
- | | a | | c | |
- | l | | b | | d |
+ | | c | | a | |
+ | j | | b | | f |
| | k | | e | |
- | j | | h | | f |
- | | i | | g | |
+ | l | | h | | d |
+ | | g | | i | |
And the ways
| nodes | junction | oneway |
@@ -151,23 +144,118 @@ Feature: Basic Roundabout
| def | | yes |
| ghi | | yes |
| jkl | | yes |
- | behkb | roundabout | yes |
+ | bkheb | roundabout | yes |
When I route I should get
| waypoints | route | turns |
| a,c | abc,abc,abc | depart,roundabout-exit-1,arrive |
- | a,f | abc,def,def | depart,roundabout-exit-2,arrive |
+ | a,l | abc,jkl,jkl | depart,roundabout-exit-2,arrive |
| a,i | abc,ghi,ghi | depart,roundabout-exit-3,arrive |
- | a,l | abc,jkl,jkl | depart,roundabout-exit-4,arrive |
+ | a,f | abc,def,def | depart,roundabout-exit-4,arrive |
| d,f | def,def,def | depart,roundabout-exit-1,arrive |
- | d,i | def,ghi,ghi | depart,roundabout-exit-2,arrive |
+ | d,c | def,abc,abc | depart,roundabout-exit-2,arrive |
| d,l | def,jkl,jkl | depart,roundabout-exit-3,arrive |
- | d,c | def,abc,abc | depart,roundabout-exit-4,arrive |
+ | d,i | def,ghi,ghi | depart,roundabout-exit-4,arrive |
| g,i | ghi,ghi,ghi | depart,roundabout-exit-1,arrive |
- | g,l | ghi,jkl,jkl | depart,roundabout-exit-2,arrive |
+ | g,f | ghi,def,def | depart,roundabout-exit-2,arrive |
| g,c | ghi,abc,abc | depart,roundabout-exit-3,arrive |
- | g,f | ghi,edf,edf | depart,roundabout-exit-4,arrive |
+ | g,l | ghi,jkl,jkl | depart,roundabout-exit-4,arrive |
| j,l | jkl,jkl,jkl | depart,roundabout-exit-1,arrive |
- | j,c | jkl,abc,abc | depart,roundabout-exit-2,arrive |
+ | j,i | jkl,ghi,ghi | depart,roundabout-exit-2,arrive |
| j,f | jkl,def,def | depart,roundabout-exit-3,arrive |
- | j,i | jkl,ghi,ghi | depart,roundabout-exit-4,arrive |
+ | j,c | jkl,abc,abc | depart,roundabout-exit-4,arrive |
+
+ Scenario: Collinear in X
+ Given the node map
+ | a | b | c | d | f |
+ | | | e | | |
+
+ And the ways
+ | nodes | junction |
+ | ab | |
+ | bcdb | roundabout |
+ | ce | |
+ | df | |
+
+ When I route I should get
+ | waypoints | route | turns |
+ | a,e | ab,ce,ce | depart,roundabout-exit-1,arrive |
+ | a,f | ab,df,df | depart,roundabout-exit-2,arrive |
+
+ Scenario: Collinear in Y
+ Given the node map
+ | a | |
+ | b | |
+ | c | e |
+ | d | |
+ | f | |
+
+ And the ways
+ | nodes | junction |
+ | ab | |
+ | bcdb | roundabout |
+ | ce | |
+ | df | |
+
+ When I route I should get
+ | waypoints | route | turns |
+ | a,e | ab,ce,ce | depart,roundabout-exit-1,arrive |
+ | a,f | ab,df,df | depart,roundabout-exit-2,arrive |
+
+ Scenario: Collinear in X,Y
+ Given the node map
+ | a | | |
+ | b | | |
+ | c | d | f |
+ | e | | |
+
+ And the ways
+ | nodes | junction |
+ | ab | |
+ | bcdb | roundabout |
+ | ce | |
+ | df | |
+
+ When I route I should get
+ | waypoints | route | turns |
+ | a,e | ab,ce,ce | depart,roundabout-exit-1,arrive |
+ | a,f | ab,df,df | depart,roundabout-exit-2,arrive |
+
+ Scenario: Collinear in X,Y
+ Given the node map
+ | a | | |
+ | d | | |
+ | b | c | f |
+ | e | | |
+
+ And the ways
+ | nodes | junction |
+ | ab | |
+ | bcdb | roundabout |
+ | ce | |
+ | df | |
+
+ When I route I should get
+ | waypoints | route | turns |
+ | a,e | ab,ce,ce | depart,roundabout-exit-1,arrive |
+ | a,f | ab,df,df | depart,roundabout-exit-2,arrive |
+
+ Scenario: Collinear in X,Y
+ Given the node map
+ | a | | |
+ | c | | |
+ | d | b | f |
+ | e | | |
+
+ And the ways
+ | nodes | junction |
+ | ab | |
+ | bcdb | roundabout |
+ | ce | |
+ | df | |
+
+ When I route I should get
+ | waypoints | route | turns |
+ | a,e | ab,ce,ce | depart,roundabout-exit-1,arrive |
+ | a,f | ab,df,df | depart,roundabout-exit-2,arrive |
+
diff --git a/features/guidance/suppressed.feature b/features/guidance/suppressed.feature
new file mode 100644
index 0000000..89b5865
--- /dev/null
+++ b/features/guidance/suppressed.feature
@@ -0,0 +1,66 @@
+ at routing @guidance
+Feature: Suppressed Turns
+
+ Background:
+ Given the profile "car"
+ Given a grid size of 10 meters
+
+ Scenario: Do not announce passing a exit ramp
+ Given the node map
+ | a | b | c | d | e |
+ | | | | f | g |
+
+ And the ways
+ | nodes | highway |
+ | abcde | motorway |
+ | bfg | motorway_link |
+
+ When I route I should get
+ | waypoints | route | turns |
+ | a,e | abcde,abcde | depart,arrive |
+
+ Scenario: Do not announce reference changes
+ Given the node map
+ | a | b | c | d | e | f |
+
+ And the ways
+ | nodes | highway | name | ref |
+ | ab | motorway | highway | A1 |
+ | bc | motorway | highway | A1,A2 |
+ | cd | motorway | highway | A2 |
+ | de | motorway | highway | |
+ | ef | motorway | highway | A1 |
+
+ When I route I should get
+ | waypoints | route | turns |
+ | a,f | highway (A1),highway (A1) | depart,arrive |
+
+
+ Scenario: Don't Announce Turn on following major road class -- service
+ Given the node map
+ | a | b | d |
+ | | | c |
+
+ And the ways
+ | nodes | highway |
+ | abc | primary |
+ | bd | service |
+
+ When I route I should get
+ | waypoints | route | turns |
+ | a,c | abc,abc | depart,arrive |
+
+ Scenario: Don't Announce Turn on following major road class -- residential
+ Given the node map
+ | a | b | d |
+ | | | c |
+
+ And the ways
+ | nodes | highway |
+ | abc | primary |
+ | bd | residential |
+
+ When I route I should get
+ | waypoints | route | turns |
+ | a,c | abc,abc | depart,arrive |
+ | a,d | abc,bd,bd | depart,turn straight,arrive |
diff --git a/features/guidance/turn.feature b/features/guidance/turn.feature
new file mode 100644
index 0000000..3eb5fc3
--- /dev/null
+++ b/features/guidance/turn.feature
@@ -0,0 +1,284 @@
+ at routing @guidance
+Feature: Simple Turns
+
+ Background:
+ Given the profile "car"
+ Given a grid size of 10 meters
+
+ Scenario: Four Way Intersection
+ Given the node map
+ | | c | |
+ | a | b | e |
+ | | d | |
+
+ And the ways
+ | nodes | highway |
+ | ab | primary |
+ | cb | primary |
+ | db | primary |
+ | eb | primary |
+
+ When I route I should get
+ | waypoints | route | turns |
+ | a,c | ab,cb,cb | depart,turn left,arrive |
+ | a,e | ab,eb,eb | depart,new name straight,arrive |
+ | a,d | ab,db,db | depart,turn right,arrive |
+ | c,a | cb,ab,ab | depart,turn right,arrive |
+ | c,d | cb,db,db | depart,new name straight,arrive |
+ | c,e | cb,eb,eb | depart,turn left,arrive |
+ | d,a | db,ab,ab | depart,turn left,arrive |
+ | d,c | db,cb,cb | depart,new name straight,arrive |
+ | d,e | db,eb,eb | depart,turn right,arrive |
+ | e,a | eb,ab,ab | depart,new name straight,arrive |
+ | e,c | eb,cb,cb | depart,turn right,arrive |
+ | e,d | eb,db,db | depart,turn left,arrive |
+
+ Scenario: Rotated Four Way Intersection
+ Given the node map
+ | a | | c |
+ | | b | |
+ | d | | e |
+
+ And the ways
+ | nodes | highway |
+ | ab | primary |
+ | cb | primary |
+ | db | primary |
+ | eb | primary |
+
+ When I route I should get
+ | waypoints | route | turns |
+ | a,c | ab,cb,cb | depart,turn left,arrive |
+ | a,e | ab,eb,eb | depart,new name straight,arrive |
+ | a,d | ab,db,db | depart,turn right,arrive |
+ | c,a | cb,ab,ab | depart,turn right,arrive |
+ | c,d | cb,db,db | depart,new name straight,arrive |
+ | c,e | cb,eb,eb | depart,turn left,arrive |
+ | d,a | db,ab,ab | depart,turn left,arrive |
+ | d,c | db,cb,cb | depart,new name straight,arrive |
+ | d,e | db,eb,eb | depart,turn right,arrive |
+ | e,a | eb,ab,ab | depart,new name straight,arrive |
+ | e,c | eb,cb,cb | depart,turn right,arrive |
+ | e,d | eb,db,db | depart,turn left,arrive |
+
+
+ Scenario: Four Way Intersection Through Street
+ Given the node map
+ | | c | |
+ | a | b | e |
+ | | d | |
+
+ And the ways
+ | nodes | highway |
+ | abe | primary |
+ | cb | primary |
+ | db | primary |
+
+ When I route I should get
+ | waypoints | route | turns |
+ | a,c | abe,cb,cb | depart,turn left,arrive |
+ | a,e | abe,abe | depart,arrive |
+ | a,d | abe,db,db | depart,turn right,arrive |
+ | c,a | cb,abe,abe | depart,turn right,arrive |
+ | c,d | cb,db,db | depart,new name straight,arrive |
+ | c,e | cb,abe,abe | depart,turn left,arrive |
+ | d,a | db,abe,abe | depart,turn left,arrive |
+ | d,c | db,cb,cb | depart,new name straight,arrive |
+ | d,e | db,abe,abe | depart,turn right,arrive |
+ | e,a | abe,abe | depart,arrive |
+ | e,c | abe,cb,cb | depart,turn right,arrive |
+ | e,d | abe,db,db | depart,turn left,arrive |
+
+ Scenario: Four Way Intersection Double Through Street
+ Given the node map
+ | | c | |
+ | a | b | e |
+ | | d | |
+
+ And the ways
+ | nodes | highway |
+ | abe | primary |
+ | cbd | primary |
+
+ When I route I should get
+ | waypoints | route | turns |
+ | a,c | abe,cbd,cbd | depart,turn left,arrive |
+ | a,e | abe,abe | depart,arrive |
+ | a,d | abe,cbd,cbd | depart,turn right,arrive |
+ | c,a | cbd,abe,abe | depart,turn right,arrive |
+ | c,d | cbd,cbd | depart,arrive |
+ | c,e | cbd,abe,abe | depart,turn left,arrive |
+ | d,a | cbd,abe,abe | depart,turn left,arrive |
+ | d,c | cbd,cbd | depart,arrive |
+ | d,e | cbd,abe,abe | depart,turn right,arrive |
+ | e,a | abe,abe | depart,arrive |
+ | e,c | abe,cbd,cbd | depart,turn right,arrive |
+ | e,d | abe,cbd,cbd | depart,turn left,arrive |
+
+ Scenario: Three Way Intersection
+ Given the node map
+ | | c | |
+ | a | b | d |
+
+ And the ways
+ | nodes | highway |
+ | ab | primary |
+ | cb | primary |
+ | db | primary |
+
+ When I route I should get
+ | waypoints | route | turns |
+ | a,c | ab,cb,cb | depart,turn left,arrive |
+ | a,d | ab,db,db | depart,new name straight,arrive |
+ | d,c | db,cb,cb | depart,turn right,arrive |
+ | d,a | db,ab,ab | depart,new name straight,arrive |
+
+ Scenario: Three Way Intersection on Through Street
+ Given the node map
+ | | d | |
+ | a | b | c |
+
+ And the ways
+ | nodes | highway |
+ | abc | primary |
+ | db | primary |
+
+ When I route I should get
+ | waypoints | route | turns |
+ | a,c | abc,abc | depart,arrive |
+ | a,d | abc,db,db | depart,turn left,arrive |
+ | c,a | abc,abc | depart,arrive |
+ | c,d | abc,db,db | depart,turn right,arrive |
+
+ Scenario: High Degree Intersection
+ Given the node map
+ | i | | b | | c |
+ | | | | | |
+ | | | | | |
+ | h | | a | | d |
+ | | | | | |
+ | | | | | |
+ | g | | f | | e |
+
+ And the ways
+ | nodes | highway |
+ | ab | primary |
+ | ac | primary |
+ | ad | primary |
+ | ae | primary |
+ | af | primary |
+ | ag | primary |
+ | ah | primary |
+ | ai | primary |
+
+ When I route I should get
+ | waypoints | route | turns |
+ | b,c | ab,ac,ac | depart,turn sharp left,arrive |
+ | b,d | ab,ad,ad | depart,turn left,arrive |
+ | b,e | ab,ae,ae | depart,turn slight left,arrive |
+ | b,f | ab,af,af | depart,new name straight,arrive |
+ | b,g | ab,ag,ag | depart,turn slight right,arrive |
+ | b,h | ab,ah,ah | depart,turn right,arrive |
+ | b,i | ab,ai,ai | depart,turn sharp right,arrive |
+
+ Scenario: Disturbed High Degree Intersection
+ Given the node map
+ | | | b | | |
+ | i | | | | c |
+ | | | | | |
+ | h | | a | | d |
+ | | | | | |
+ | g | | | | e |
+ | | | f | | |
+
+ And the ways
+ | nodes | highway |
+ | ab | primary |
+ | ac | primary |
+ | ad | primary |
+ | ae | primary |
+ | af | primary |
+ | ag | primary |
+ | ah | primary |
+ | ai | primary |
+
+ When I route I should get
+ | waypoints | route | turns |
+ | b,c | ab,ac,ac | depart,turn sharp left,arrive |
+ | b,d | ab,ad,ad | depart,turn left,arrive |
+ | b,e | ab,ae,ae | depart,turn slight left,arrive |
+ | b,f | ab,af,af | depart,new name straight,arrive |
+ | b,g | ab,ag,ag | depart,turn slight right,arrive |
+ | b,h | ab,ah,ah | depart,turn right,arrive |
+ | b,i | ab,ai,ai | depart,turn sharp right,arrive |
+
+ Scenario: Turn instructions at high latitude
+ Given the node locations
+ | node | lat | lon |
+ | a | 55.68740 | 12.52430 |
+ | b | 55.68745 | 12.52409 |
+ | c | 55.68711 | 12.52383 |
+ | d | 55.68745 | 12.52450 |
+ | e | 55.68755 | 12.52450 |
+ | x | -55.68740 | 12.52430 |
+ | y | -55.68745 | 12.52409 |
+ | z | -55.68711 | 12.52383 |
+ | v | -55.68745 | 12.52450 |
+ | w | -55.68755 | 12.52450 |
+
+ And the ways
+ | nodes |
+ | ab |
+ | bc |
+ | bd |
+ | be |
+ | xy |
+ | yz |
+ | vy |
+ | wy |
+
+ When I route I should get
+ | from | to | route | turns |
+ | a | c | ab,bc,bc | depart,turn left,arrive |
+ | c | a | bc,ab,ab | depart,turn right,arrive |
+ | x | z | xy,yz,yz | depart,turn right,arrive |
+ | z | x | yz,xy,xy | depart,turn left,arrive |
+
+ Scenario: Four Way Intersection Double Through Street Segregated
+ Given the node map
+ | | b | | c | |
+ | i | | | | d |
+ | | | a | | |
+ | h | | | | e |
+ | | g | | f | |
+
+ And the ways
+ | nodes | highway | oneway | name |
+ | ha | primary | yes | first |
+ | ai | primary | yes | first |
+ | ae | primary | yes | first |
+ | da | primary | yes | first |
+ | ba | primary | yes | second |
+ | ac | primary | yes | second |
+ | fa | primary | yes | second |
+ | ag | primary | yes | second |
+
+ When I route I should get
+ | waypoints | route | turns |
+ | f,e | second,first,first | depart,turn right,arrive |
+ | f,c | second,second | depart,arrive |
+ | f,i | second,first,first | depart,turn left,arrive |
+ | f,g | second,second,second | depart,continue uturn,arrive |
+ | d,c | first,second,second | depart,turn right,arrive |
+ | d,i | first,first | depart,arrive |
+ | d,g | first,second,second | depart,turn left,arrive |
+ | d,e | first,first,first | depart,continue uturn,arrive |
+ | b,i | second,first,first | depart,turn right,arrive |
+ | b,g | second,second | depart,arrive |
+ | b,e | second,first,first | depart,turn left,arrive |
+ | b,c | second,second,second | depart,continue uturn,arrive |
+ | h,g | first,second,second | depart,turn right,arrive |
+ | h,e | first,first | depart,arrive |
+ | h,c | first,second,second | depart,turn left,arrive |
+ | h,i | first,first,first | depart,continue uturn,arrive |
+
diff --git a/features/step_definitions/requests.js b/features/step_definitions/requests.js
index dcaf5cc..99adee6 100644
--- a/features/step_definitions/requests.js
+++ b/features/step_definitions/requests.js
@@ -44,12 +44,9 @@ module.exports = function () {
this.Then(/^response should be a well-formed route$/, () => {
this.ShouldBeWellFormed();
- assert.equal(typeof this.json.status_message, 'string');
- assert.equal(typeof this.json.route_summary, 'object');
- assert.equal(typeof this.json.route_geometry, 'string');
- assert.ok(Array.isArray(this.json.route_instructions));
- assert.ok(Array.isArray(this.json.via_points));
- assert.ok(Array.isArray(this.json.via_indices));
+ assert.equal(this.json.code, 'ok');
+ assert.ok(Array.isArray(this.json.routes));
+ assert.ok(Array.isArray(this.json.waypoints));
});
this.Then(/^"([^"]*)" should return code (\d+)$/, (binary, code) => {
diff --git a/features/step_definitions/trip.js b/features/step_definitions/trip.js
index b1727da..9662ac6 100644
--- a/features/step_definitions/trip.js
+++ b/features/step_definitions/trip.js
@@ -110,6 +110,7 @@ module.exports = function () {
} else {
var params = this.queryParams,
waypoints = [];
+ params['steps'] = 'true';
if (row.from && row.to) {
var fromNode = this.findNodeByName(row.from);
if (!fromNode) throw new Error(util.format('*** unknown from-node "%s"', row.from));
diff --git a/features/support/env.js b/features/support/env.js
index cae361c..5a337bc 100644
--- a/features/support/env.js
+++ b/features/support/env.js
@@ -7,7 +7,8 @@ var d3 = require('d3-queue');
module.exports = function () {
this.initializeEnv = (callback) => {
this.DEFAULT_PORT = 5000;
- this.DEFAULT_TIMEOUT = 2000;
+ // OSX builds on Travis hit a timeout of ~2000 from time to time
+ this.DEFAULT_TIMEOUT = 5000;
this.setDefaultTimeout(this.DEFAULT_TIMEOUT);
this.ROOT_FOLDER = process.cwd();
this.OSM_USER = 'osrm';
diff --git a/features/support/route.js b/features/support/route.js
index 7c208ff..1dbce8c 100644
--- a/features/support/route.js
+++ b/features/support/route.js
@@ -144,9 +144,14 @@ module.exports = function () {
return v.maneuver.type;
case 'roundabout':
return 'roundabout-exit-' + v.maneuver.exit;
+ case 'rotary':
+ if( 'rotary_name' in v )
+ return v.rotary_name + '-exit-' + v.maneuver.exit;
+ else
+ return 'rotary-exit-' + v.maneuver.exit;
// FIXME this is a little bit over-simplistic for merge/fork instructions
default:
- return v.maneuver.modifier;
+ return v.maneuver.type + ' ' + v.maneuver.modifier;
}
})
.join(',');
diff --git a/features/support/shared_steps.js b/features/support/shared_steps.js
index 5751492..b0be24b 100644
--- a/features/support/shared_steps.js
+++ b/features/support/shared_steps.js
@@ -35,7 +35,7 @@ module.exports = function () {
var json = JSON.parse(body);
- var hasRoute = json.code === 'ok';
+ var hasRoute = json.code === 'Ok';
if (hasRoute) {
instructions = this.wayList(json.routes[0]);
@@ -59,14 +59,6 @@ module.exports = function () {
got['#'] = row['#'];
}
- if (headers.has('start')) {
- got.start = instructions ? json.route_summary.start_point : null;
- }
-
- if (headers.has('end')) {
- got.end = instructions ? json.route_summary.end_point : null;
- }
-
if (headers.has('geometry')) {
got.geometry = json.routes[0].geometry;
}
diff --git a/features/testbot/graph.feature b/features/testbot/graph.feature
index f86b994..81741aa 100644
--- a/features/testbot/graph.feature
+++ b/features/testbot/graph.feature
@@ -36,5 +36,5 @@ Feature: Basic Routing
| fy | last |
When I route I should get
- | from | to | route | turns |
- | x | y | first,compr,last,last | depart,right,left,arrive |
+ | from | to | route |
+ | x | y | first,compr,last,last |
diff --git a/features/testbot/matching.feature b/features/testbot/matching.feature
index bee3d9c..71ac077 100644
--- a/features/testbot/matching.feature
+++ b/features/testbot/matching.feature
@@ -85,3 +85,22 @@ Feature: Basic Map Matching
| trace | matchings |
| dcba | hgfe |
+ Scenario: Testbot - Matching with oneway streets
+ Given a grid size of 10 meters
+ Given the node map
+ | a | b | c | d |
+ | e | f | g | h |
+
+ And the ways
+ | nodes | oneway |
+ | ab | yes |
+ | bc | yes |
+ | cd | yes |
+ | hg | yes |
+ | gf | yes |
+ | fe | yes |
+
+ When I match I should get
+ | trace | matchings |
+ | dcba | hg,gf,fe |
+ | efgh | ab,bc,cd |
diff --git a/features/testbot/overlap.feature b/features/testbot/overlap.feature
index 509867f..c76cff2 100644
--- a/features/testbot/overlap.feature
+++ b/features/testbot/overlap.feature
@@ -1,10 +1,9 @@
- at routing @testbot @overlap
+ at routing @testbot @overlap @todo
Feature: Testbot - overlapping ways
-
+
Background:
Given the profile "testbot"
- @bug @610
Scenario: Testbot - multiple way between same nodes
Note that cb is connecting the same two nodes as bc
Given the node map
@@ -18,11 +17,10 @@ Feature: Testbot - overlapping ways
| cb | secondary |
When I route I should get
- | from | to | route |
- | a | d | ab,bc,cd |
- | d | a | cd,bc,ab |
-
- @bug @610
+ | from | to | route |
+ | a | d | ab,bc,cd,cd |
+ | d | a | cd,bc,ab,ab |
+
Scenario: Testbot - area on top of way
Given the node map
| x | a | b | y |
@@ -34,6 +32,6 @@ Feature: Testbot - overlapping ways
| abcda | secondary | yes |
When I route I should get
- | from | to | route |
- | x | y | xaby |
- | y | x | xaby |
+ | from | to | route |
+ | x | y | xaby,xaby |
+ | y | x | xaby,xaby |
diff --git a/features/testbot/roundabout.feature b/features/testbot/roundabout.feature
deleted file mode 100644
index 90f2fc0..0000000
--- a/features/testbot/roundabout.feature
+++ /dev/null
@@ -1,76 +0,0 @@
- at routing @testbot @roundabout @instruction
-Feature: Roundabout Instructions
-
- Background:
- Given the profile "testbot"
-
- Scenario: Testbot - Roundabout
- Given the node map
- | | | v | | |
- | | | d | | |
- | s | a | | c | u |
- | | | b | | |
- | | | t | | |
-
- And the ways
- | nodes | junction |
- | sa | |
- | tb | |
- | uc | |
- | vd | |
- | abcda | roundabout |
-
- When I route I should get
- | from | to | route | turns |
- | s | t | sa,tb,tb | depart,roundabout-exit-1,arrive |
- | s | u | sa,uc,uc | depart,roundabout-exit-2,arrive |
- | s | v | sa,vd,vd | depart,roundabout-exit-3,arrive |
- | t | u | tb,uc,uc | depart,roundabout-exit-1,arrive |
- | t | v | tb,vd,vd | depart,roundabout-exit-2,arrive |
- | t | s | tb,sa,sa | depart,roundabout-exit-3,arrive |
- | u | v | uc,vd,vd | depart,roundabout-exit-1,arrive |
- | u | s | uc,sa,sa | depart,roundabout-exit-2,arrive |
- | u | t | uc,tb,tb | depart,roundabout-exit-3,arrive |
- | v | s | vd,sa,sa | depart,roundabout-exit-1,arrive |
- | v | t | vd,tb,tb | depart,roundabout-exit-2,arrive |
- | v | u | vd,uc,uc | depart,roundabout-exit-3,arrive |
-
- Scenario: Testbot - Roundabout with oneway links
- Given the node map
- | | | p | o | | |
- | | | h | g | | |
- | i | a | | | f | n |
- | j | b | | | e | m |
- | | | c | d | | |
- | | | k | l | | |
-
- And the ways
- | nodes | junction | oneway |
- | ai | | yes |
- | jb | | yes |
- | ck | | yes |
- | ld | | yes |
- | em | | yes |
- | nf | | yes |
- | go | | yes |
- | ph | | yes |
- | abcdefgha | roundabout | |
-
- When I route I should get
- | from | to | route | turns |
- | j | k | jb,ck,ck | depart,roundabout-exit-1,arrive |
- | j | m | jb,em,em | depart,roundabout-exit-2,arrive |
- | j | o | jb,go,go | depart,roundabout-exit-3,arrive |
- | j | i | jb,ai,ai | depart,roundabout-exit-4,arrive |
- | l | m | ld,em,em | depart,roundabout-exit-1,arrive |
- | l | o | ld,go,go | depart,roundabout-exit-2,arrive |
- | l | i | ld,ai,ai | depart,roundabout-exit-3,arrive |
- | l | k | ld,ck,ck | depart,roundabout-exit-4,arrive |
- | n | o | nf,go,go | depart,roundabout-exit-1,arrive |
- | n | i | nf,ai,ai | depart,roundabout-exit-2,arrive |
- | n | k | nf,ck,ck | depart,roundabout-exit-3,arrive |
- | n | m | nf,em,em | depart,roundabout-exit-4,arrive |
- | p | i | ph,ai,ai | depart,roundabout-exit-1,arrive |
- | p | k | ph,ck,ck | depart,roundabout-exit-2,arrive |
- | p | m | ph,em,em | depart,roundabout-exit-3,arrive |
- | p | o | ph,go,go | depart,roundabout-exit-4,arrive |
diff --git a/features/testbot/status.feature b/features/testbot/status.feature
index 41ad18b..2221461 100644
--- a/features/testbot/status.feature
+++ b/features/testbot/status.feature
@@ -46,22 +46,22 @@ Feature: Status messages
| ab |
When I route I should get
- | request | status | message |
- | route/v1/driving/1,1;1,2 | 200 | |
- | nonsense | 400 | URL string malformed close to position 0: "/no" |
- | nonsense/v1/driving/1,1;1,2 | 400 | Service nonsense not found! |
- | | 400 | URL string malformed close to position 0: "/" |
- | / | 400 | URL string malformed close to position 0: "//" |
- | ? | 400 | URL string malformed close to position 0: "/?" |
- | route/v1/driving | 400 | URL string malformed close to position 0: "/ro" |
- | route/v1/driving/ | 400 | URL string malformed close to position 0: "/ro" |
- | route/v1/driving/1 | 400 | Query string malformed close to position 0 |
- | route/v1/driving/1,1 | 400 | Number of coordinates needs to be at least two. |
- | route/v1/driving/1,1,1 | 400 | Query string malformed close to position 3 |
- | route/v1/driving/x | 400 | Query string malformed close to position 0 |
- | route/v1/driving/x,y | 400 | Query string malformed close to position 0 |
- | route/v1/driving/1,1; | 400 | Query string malformed close to position 3 |
- | route/v1/driving/1,1;1 | 400 | Query string malformed close to position 3 |
- | route/v1/driving/1,1;1,1,1 | 400 | Query string malformed close to position 7 |
- | route/v1/driving/1,1;x | 400 | Query string malformed close to position 3 |
- | route/v1/driving/1,1;x,y | 400 | Query string malformed close to position 3 |
+ | request | status | message |
+ | route/v1/driving/1,1;1,2 | 200 | |
+ | nonsense | 400 | URL string malformed close to position 9: "nse" |
+ | nonsense/v1/driving/1,1;1,2 | 400 | Service nonsense not found! |
+ | | 400 | URL string malformed close to position 1: "/" |
+ | / | 400 | URL string malformed close to position 1: "//" |
+ | ? | 400 | URL string malformed close to position 1: "/?" |
+ | route/v1/driving | 400 | URL string malformed close to position 17: "ing" |
+ | route/v1/driving/ | 400 | URL string malformed close to position 18: "ng/" |
+ | route/v1/driving/1 | 400 | Query string malformed close to position 1 |
+ | route/v1/driving/1,1 | 400 | Number of coordinates needs to be at least two. |
+ | route/v1/driving/1,1,1 | 400 | Query string malformed close to position 3 |
+ | route/v1/driving/x | 400 | Query string malformed close to position 0 |
+ | route/v1/driving/x,y | 400 | Query string malformed close to position 0 |
+ | route/v1/driving/1,1; | 400 | Query string malformed close to position 3 |
+ | route/v1/driving/1,1;1 | 400 | Query string malformed close to position 5 |
+ | route/v1/driving/1,1;1,1,1 | 400 | Query string malformed close to position 7 |
+ | route/v1/driving/1,1;x | 400 | Query string malformed close to position 3 |
+ | route/v1/driving/1,1;x,y | 400 | Query string malformed close to position 3 |
diff --git a/features/testbot/turn_angles.feature b/features/testbot/turn_angles.feature
deleted file mode 100644
index 115fd23..0000000
--- a/features/testbot/turn_angles.feature
+++ /dev/null
@@ -1,74 +0,0 @@
- at routing @testbot @via
-Feature: Via points
-
- Background:
- Given the profile "testbot"
-
- And a grid size of 4 meters
-
- Scenario: Basic Right Turn
- Given the node map
- | a | b | c | d | e | f | g |
- | | | | | | h | |
- | | | | | | i | |
- | | | | | | j | |
- | | | | | | k | |
-
- And the ways
- | nodes | oneway |
- | abcdefg | yes |
- | ehijk | yes |
-
- When I route I should get
- | from | to | route | distance | turns |
- | a | k | abcdefg,ehijk,ehijk | 34m +-1 | depart,right,arrive |
-
- Scenario: Slight Turn
- Given the node map
- | a | b | c | d | e | f | g | |
- | | | | | | h | i | |
- | | | | | | | | j |
- | | | | | | | | k |
-
- And the ways
- | nodes | oneway |
- | abcdefg | yes |
- | ehijk | yes |
-
- When I route I should get
- | from | to | route | distance | turns |
- | a | k | abcdefg,ehijk,ehijk | 35m +-1 | depart,slight right,arrive |
-
- Scenario: Nearly Slight Turn
- Given the node map
- | a | b | c | d | e | f | g | |
- | | | | | | h | | |
- | | | | | | | i | |
- | | | | | | | | j |
- | | | | | | | | k |
-
- And the ways
- | nodes | oneway |
- | abcdefg | yes |
- | ehijk | yes |
-
- When I route I should get
- | from | to | route | distance | turns |
- | a | k | abcdefg,ehijk,ehijk | 37m +-1 | depart,right,arrive |
-
- Scenario: Nearly Slight Turn (Variation)
- Given the node map
- | a | b | c | d | e | f | g | |
- | | | | | | h | | |
- | | | | | | | i | |
- | | | | | | | j | |
- | | | | | | | | k |
-
- And the ways
- | nodes | oneway |
- | abcdefg | yes |
- | ehijk | yes |
-
- When I route I should get
- | from | to | route | distance | turns |
- | a | k | abcdefg,ehijk,ehijk | 37m +-1 | depart,right,arrive |
diff --git a/features/testbot/turns.feature b/features/testbot/turns.feature
deleted file mode 100644
index c80bdf7..0000000
--- a/features/testbot/turns.feature
+++ /dev/null
@@ -1,115 +0,0 @@
- at routing @turns @testbot
-Feature: Turn directions/codes
-
- Background:
- Given the profile "testbot"
-
- Scenario: Turn directions
- Given the node map
- | o | p | a | b | c |
- | n | | | | d |
- | m | | x | | e |
- | l | | | | f |
- | k | j | i | h | g |
-
- And the ways
- | nodes |
- | xi |
- | xk |
- | xm |
- | xo |
- | xa |
- | xc |
- | xe |
- | xg |
-
- When I route I should get
- | from | to | route | turns |
- | i | k | xi,xk,xk | depart,sharp left,arrive |
- | i | m | xi,xm,xm | depart,left,arrive |
- | i | o | xi,xo,xo | depart,slight left,arrive |
- | i | a | xi,xa,xa | depart,straight,arrive |
- | i | c | xi,xc,xc | depart,slight right,arrive |
- | i | e | xi,xe,xe | depart,right,arrive |
- | i | g | xi,xg,xg | depart,sharp right,arrive |
-
- | k | m | xk,xm,xm | depart,sharp left,arrive |
- | k | o | xk,xo,xo | depart,left,arrive |
- | k | a | xk,xa,xa | depart,slight left,arrive |
- | k | c | xk,xc,xc | depart,straight,arrive |
- | k | e | xk,xe,xe | depart,slight right,arrive |
- | k | g | xk,xg,xg | depart,right,arrive |
- | k | i | xk,xi,xi | depart,sharp right,arrive |
-
- | m | o | xm,xo,xo | depart,sharp left,arrive |
- | m | a | xm,xa,xa | depart,left,arrive |
- | m | c | xm,xc,xc | depart,slight left,arrive |
- | m | e | xm,xe,xe | depart,straight,arrive |
- | m | g | xm,xg,xg | depart,slight right,arrive |
- | m | i | xm,xi,xi | depart,right,arrive |
- | m | k | xm,xk,xk | depart,sharp right,arrive |
-
- | o | a | xo,xa,xa | depart,sharp left,arrive |
- | o | c | xo,xc,xc | depart,left,arrive |
- | o | e | xo,xe,xe | depart,slight left,arrive |
- | o | g | xo,xg,xg | depart,straight,arrive |
- | o | i | xo,xi,xi | depart,slight right,arrive |
- | o | k | xo,xk,xk | depart,right,arrive |
- | o | m | xo,xm,xm | depart,sharp right,arrive |
-
- | a | c | xa,xc,xc | depart,sharp left,arrive |
- | a | e | xa,xe,xe | depart,left,arrive |
- | a | g | xa,xg,xg | depart,slight left,arrive |
- | a | i | xa,xi,xi | depart,straight,arrive |
- | a | k | xa,xk,xk | depart,slight right,arrive |
- | a | m | xa,xm,xm | depart,right,arrive |
- | a | o | xa,xo,xo | depart,sharp right,arrive |
-
- | c | e | xc,xe,xe | depart,sharp left,arrive |
- | c | g | xc,xg,xg | depart,left,arrive |
- | c | i | xc,xi,xi | depart,slight left,arrive |
- | c | k | xc,xk,xk | depart,straight,arrive |
- | c | m | xc,xm,xm | depart,slight right,arrive |
- | c | o | xc,xo,xo | depart,right,arrive |
- | c | a | xc,xa,xa | depart,sharp right,arrive |
-
- | e | g | xe,xg,xg | depart,sharp left,arrive |
- | e | i | xe,xi,xi | depart,left,arrive |
- | e | k | xe,xk,xk | depart,slight left,arrive |
- | e | m | xe,xm,xm | depart,straight,arrive |
- | e | o | xe,xo,xo | depart,slight right,arrive |
- | e | a | xe,xa,xa | depart,right,arrive |
- | e | c | xe,xc,xc | depart,sharp right,arrive |
-
- | g | i | xg,xi,xi | depart,sharp left,arrive |
- | g | k | xg,xk,xk | depart,left,arrive |
- | g | m | xg,xm,xm | depart,slight left,arrive |
- | g | o | xg,xo,xo | depart,straight,arrive |
- | g | a | xg,xa,xa | depart,slight right,arrive |
- | g | c | xg,xc,xc | depart,right,arrive |
- | g | e | xg,xe,xe | depart,sharp right,arrive |
-
- Scenario: Turn instructions at high latitude
- # https://github.com/DennisOSRM/Project-OSRM/issues/532
- Given the node locations
- | node | lat | lon |
- | a | 55.68740 | 12.52430 |
- | b | 55.68745 | 12.52409 |
- | c | 55.68711 | 12.52383 |
- | x | -55.68740 | 12.52430 |
- | y | -55.68745 | 12.52409 |
- | z | -55.68711 | 12.52383 |
-
- And the ways
- | nodes |
- | ab |
- | bc |
- | xy |
- | yz |
-
- When I route I should get
- | from | to | route | turns |
- | a | c | ab,bc,bc | depart,left,arrive |
- | c | a | bc,ab,ab | depart,right,arrive |
- | x | z | xy,yz,yz | depart,right,arrive |
- | z | x | yz,xy,xy | depart,left,arrive |
diff --git a/features/testbot/uturn.feature b/features/testbot/uturn.feature
deleted file mode 100644
index f00f5fc..0000000
--- a/features/testbot/uturn.feature
+++ /dev/null
@@ -1,93 +0,0 @@
- at routing @uturn @via @testbot
-Feature: U-turns at via points
-
- Background:
- Given the profile "testbot"
-
- Scenario: U-turns at via points disabled by default
- Given the node map
- | a | b | c | d |
- | | e | f | g |
-
- And the ways
- | nodes |
- | ab |
- | bc |
- | cd |
- | be |
- | dg |
- | ef |
- | fg |
-
- When I route I should get
- | waypoints | route | turns |
- | a,e,c | ab,be,be,ef,fg,dg,cd,cd | depart,right,arrive,depart,straight,left,left,arrive |
-
- Scenario: Query param to allow U-turns at all via points
- Given the node map
- | a | b | c | d |
- | | e | f | g |
-
- And the query options
- | uturns | true |
-
- And the ways
- | nodes |
- | ab |
- | bc |
- | cd |
- | be |
- | dg |
- | ef |
- | fg |
-
- When I route I should get
- | waypoints | route |
- | a,e,c | ab,be,be,be,bc,bc |
-
- @todo
- Scenario: Instructions at via points at u-turns
- Given the node map
- | a | b | c | d |
- | | e | f | g |
-
- And the query options
- | uturns | true |
-
- And the ways
- | nodes |
- | ab |
- | bc |
- | cd |
- | be |
- | dg |
- | ef |
- | fg |
-
- When I route I should get
- | waypoints | route | turns |
- | a,e,c | ab,be,be,bc,bc | depart,right,uturn,right,arrive |
-
- Scenario: u-turn mixed with non-uturn vias
- Given the node map
- | a | 1 | b | 3 | c | 5 | d |
- | | | 2 | | | | 4 |
- | | | e | | f | | g |
-
- And the query options
- | uturns | true |
-
- And the ways
- | nodes |
- | ab |
- | bc |
- | cd |
- | be |
- | dg |
- | ef |
- | fg |
-
- When I route I should get
- | waypoints | route |
- | 1,2,3,4,5 | ab,be,be,be,bc,bc,bc,be,ef,fg,dg,dg,dg,cd,cd |
-
diff --git a/include/contractor/graph_contractor.hpp b/include/contractor/graph_contractor.hpp
index 26be61d..ce33d26 100644
--- a/include/contractor/graph_contractor.hpp
+++ b/include/contractor/graph_contractor.hpp
@@ -342,7 +342,7 @@ class GraphContractor
// remaining graph
std::vector<NodeID> new_node_id_from_orig_id_map(number_of_nodes, SPECIAL_NODEID);
- for (const auto new_node_id : util::irange<std::size_t>(0, remaining_nodes.size()))
+ for (const auto new_node_id : util::irange<std::size_t>(0UL, remaining_nodes.size()))
{
auto &node = remaining_nodes[new_node_id];
BOOST_ASSERT(node_priorities.size() > node.id);
@@ -352,7 +352,7 @@ class GraphContractor
}
// build forward and backward renumbering map and remap ids in remaining_nodes
- for (const auto new_node_id : util::irange<std::size_t>(0, remaining_nodes.size()))
+ for (const auto new_node_id : util::irange<std::size_t>(0UL, remaining_nodes.size()))
{
auto &node = remaining_nodes[new_node_id];
// create renumbering maps in both directions
@@ -362,7 +362,7 @@ class GraphContractor
}
// walk over all nodes
for (const auto source :
- util::irange<NodeID>(0, contractor_graph->GetNumberOfNodes()))
+ util::irange<NodeID>(0UL, contractor_graph->GetNumberOfNodes()))
{
for (auto current_edge : contractor_graph->GetAdjacentEdgeRange(source))
{
diff --git a/include/engine/api/json_factory.hpp b/include/engine/api/json_factory.hpp
index 49e81f2..0b1e5f3 100644
--- a/include/engine/api/json_factory.hpp
+++ b/include/engine/api/json_factory.hpp
@@ -14,8 +14,9 @@
#include <boost/optional.hpp>
-#include <string>
#include <algorithm>
+#include <iterator>
+#include <string>
#include <vector>
namespace osrm
diff --git a/include/engine/api/match_api.hpp b/include/engine/api/match_api.hpp
index 7ce4fa2..46b26ae 100644
--- a/include/engine/api/match_api.hpp
+++ b/include/engine/api/match_api.hpp
@@ -45,7 +45,7 @@ class MatchAPI final : public RouteAPI
}
response.values["tracepoints"] = MakeTracepoints(sub_matchings);
response.values["matchings"] = std::move(routes);
- response.values["code"] = "ok";
+ response.values["code"] = "Ok";
}
// FIXME gcc 4.8 doesn't support for lambdas to call protected member functions
@@ -90,7 +90,7 @@ class MatchAPI final : public RouteAPI
}
}
- for (auto trace_index : util::irange(0UL, parameters.coordinates.size()))
+ for (auto trace_index : util::irange<std::size_t>(0UL, parameters.coordinates.size()))
{
auto matching_index = trace_idx_to_matching_idx[trace_index];
if (matching_index.NotMatched())
diff --git a/include/engine/api/nearest_api.hpp b/include/engine/api/nearest_api.hpp
index ab3747e..ed09f62 100644
--- a/include/engine/api/nearest_api.hpp
+++ b/include/engine/api/nearest_api.hpp
@@ -43,7 +43,7 @@ class NearestAPI final : public BaseAPI
return waypoint;
});
- response.values["code"] = "ok";
+ response.values["code"] = "Ok";
response.values["waypoints"] = std::move(waypoints);
}
diff --git a/include/engine/api/route_api.hpp b/include/engine/api/route_api.hpp
index e3b9ff8..f2b7a73 100644
--- a/include/engine/api/route_api.hpp
+++ b/include/engine/api/route_api.hpp
@@ -2,15 +2,15 @@
#define ENGINE_API_ROUTE_HPP
#include "engine/api/base_api.hpp"
-#include "engine/api/route_parameters.hpp"
#include "engine/api/json_factory.hpp"
+#include "engine/api/route_parameters.hpp"
#include "engine/datafacade/datafacade_base.hpp"
-#include "engine/guidance/assemble_leg.hpp"
-#include "engine/guidance/assemble_route.hpp"
#include "engine/guidance/assemble_geometry.hpp"
+#include "engine/guidance/assemble_leg.hpp"
#include "engine/guidance/assemble_overview.hpp"
+#include "engine/guidance/assemble_route.hpp"
#include "engine/guidance/assemble_steps.hpp"
#include "engine/guidance/post_processing.hpp"
@@ -19,6 +19,7 @@
#include "util/coordinate.hpp"
#include "util/integer_range.hpp"
+#include <iterator>
#include <vector>
namespace osrm
@@ -54,7 +55,7 @@ class RouteAPI : public BaseAPI
}
response.values["waypoints"] = BaseAPI::MakeWaypoints(raw_route.segment_end_coordinates);
response.values["routes"] = std::move(routes);
- response.values["code"] = "ok";
+ response.values["code"] = "Ok";
}
// FIXME gcc 4.8 doesn't support for lambdas to call protected member functions
@@ -82,7 +83,7 @@ class RouteAPI : public BaseAPI
legs.reserve(number_of_legs);
leg_geometries.reserve(number_of_legs);
- for (auto idx : util::irange(0UL, number_of_legs))
+ for (auto idx : util::irange<std::size_t>(0UL, number_of_legs))
{
const auto &phantoms = segment_end_coordinates[idx];
const auto &path_data = unpacked_path_segments[idx];
@@ -92,8 +93,8 @@ class RouteAPI : public BaseAPI
auto leg_geometry = guidance::assembleGeometry(
BaseAPI::facade, path_data, phantoms.source_phantom, phantoms.target_phantom);
- auto leg = guidance::assembleLeg(BaseAPI::facade, path_data, leg_geometry,
- phantoms.source_phantom, phantoms.target_phantom, reversed_target);
+ auto leg = guidance::assembleLeg(path_data, leg_geometry, phantoms.source_phantom,
+ phantoms.target_phantom, reversed_target);
if (parameters.steps)
{
@@ -155,13 +156,12 @@ class RouteAPI : public BaseAPI
}
std::vector<util::json::Value> step_geometries;
- for (const auto idx : util::irange(0UL, legs.size()))
+ for (const auto idx : util::irange<std::size_t>(0UL, legs.size()))
{
auto &leg_geometry = leg_geometries[idx];
std::transform(
legs[idx].steps.begin(), legs[idx].steps.end(), std::back_inserter(step_geometries),
- [this, &leg_geometry](const guidance::RouteStep &step)
- {
+ [this, &leg_geometry](const guidance::RouteStep &step) {
if (parameters.geometries == RouteParameters::GeometriesType::Polyline)
{
return static_cast<util::json::Value>(
diff --git a/include/engine/api/route_parameters.hpp b/include/engine/api/route_parameters.hpp
index b8704fc..5904020 100644
--- a/include/engine/api/route_parameters.hpp
+++ b/include/engine/api/route_parameters.hpp
@@ -48,7 +48,7 @@ namespace api
* - geometries: route geometry encoded in Polyline or GeoJSON
* - overview: adds overview geometry either Full, Simplified (according to highest zoom level) or
* False (not at all)
- * - uturns: enable or disable uturns (disabled by default)
+ * - continue_straight: enable or disable continue_straight (disabled by default)
*
* \see OSRM, Coordinate, Hint, Bearing, RouteParame, RouteParameters, TableParameters,
* NearestParameters, TripParameters, MatchParameters and TileParameters
@@ -74,18 +74,18 @@ struct RouteParameters : public BaseParameters
const bool alternatives_,
const GeometriesType geometries_,
const OverviewType overview_,
- const boost::optional<bool> uturns_,
+ const boost::optional<bool> continue_straight_,
Args... args_)
: BaseParameters{std::forward<Args>(args_)...}, steps{steps_}, alternatives{alternatives_},
- geometries{geometries_}, overview{overview_}, uturns{uturns_}
+ geometries{geometries_}, overview{overview_}, continue_straight{continue_straight_}
{
}
- bool steps = true;
- bool alternatives = true;
+ bool steps = false;
+ bool alternatives = false;
GeometriesType geometries = GeometriesType::Polyline;
OverviewType overview = OverviewType::Simplified;
- boost::optional<bool> uturns;
+ boost::optional<bool> continue_straight;
bool IsValid() const { return coordinates.size() >= 2 && BaseParameters::IsValid(); }
};
diff --git a/include/engine/api/table_api.hpp b/include/engine/api/table_api.hpp
index ac683c9..1655ce3 100644
--- a/include/engine/api/table_api.hpp
+++ b/include/engine/api/table_api.hpp
@@ -19,6 +19,8 @@
#include <boost/range/algorithm/transform.hpp>
+#include <iterator>
+
namespace osrm
{
namespace engine
@@ -65,7 +67,7 @@ class TableAPI final : public BaseAPI
response.values["durations"] =
MakeTable(durations, number_of_sources, number_of_destinations);
- response.values["code"] = "ok";
+ response.values["code"] = "Ok";
}
// FIXME gcc 4.8 doesn't support for lambdas to call protected member functions
@@ -103,7 +105,7 @@ class TableAPI final : public BaseAPI
std::size_t number_of_columns) const
{
util::json::Array json_table;
- for (const auto row : util::irange<std::size_t>(0, number_of_rows))
+ for (const auto row : util::irange<std::size_t>(0UL, number_of_rows))
{
util::json::Array json_row;
auto row_begin_iterator = values.begin() + (row * number_of_columns);
diff --git a/include/engine/api/trip_api.hpp b/include/engine/api/trip_api.hpp
index aea7676..9ed72ef 100644
--- a/include/engine/api/trip_api.hpp
+++ b/include/engine/api/trip_api.hpp
@@ -44,7 +44,7 @@ class TripAPI final : public RouteAPI
}
response.values["waypoints"] = MakeWaypoints(sub_trips, phantoms);
response.values["trips"] = std::move(routes);
- response.values["code"] = "ok";
+ response.values["code"] = "Ok";
}
// FIXME gcc 4.8 doesn't support for lambdas to call protected member functions
@@ -77,17 +77,17 @@ class TripAPI final : public RouteAPI
};
std::vector<TripIndex> input_idx_to_trip_idx(parameters.coordinates.size());
- for (auto sub_trip_index : util::irange(0u, static_cast<unsigned>(sub_trips.size())))
+ for (auto sub_trip_index : util::irange<unsigned>(0u, sub_trips.size()))
{
for (auto point_index :
- util::irange(0u, static_cast<unsigned>(sub_trips[sub_trip_index].size())))
+ util::irange<unsigned>(0u, sub_trips[sub_trip_index].size()))
{
input_idx_to_trip_idx[sub_trips[sub_trip_index][point_index]] =
TripIndex{sub_trip_index, point_index};
}
}
- for (auto input_index : util::irange(0UL, parameters.coordinates.size()))
+ for (auto input_index : util::irange<std::size_t>(0UL, parameters.coordinates.size()))
{
auto trip_index = input_idx_to_trip_idx[input_index];
BOOST_ASSERT(!trip_index.NotUsed());
diff --git a/include/engine/datafacade/datafacade_base.hpp b/include/engine/datafacade/datafacade_base.hpp
index f4cb0c4..1f608d9 100644
--- a/include/engine/datafacade/datafacade_base.hpp
+++ b/include/engine/datafacade/datafacade_base.hpp
@@ -144,7 +144,7 @@ class BaseDataFacade
virtual std::string GetTimestamp() const = 0;
- virtual bool GetUTurnsDefault() const = 0;
+ virtual bool GetContinueStraightDefault() const = 0;
};
}
}
diff --git a/include/engine/datafacade/internal_datafacade.hpp b/include/engine/datafacade/internal_datafacade.hpp
index 302af30..bda4869 100644
--- a/include/engine/datafacade/internal_datafacade.hpp
+++ b/include/engine/datafacade/internal_datafacade.hpp
@@ -649,7 +649,7 @@ class InternalDataFacade final : public BaseDataFacade
std::string GetTimestamp() const override final { return m_timestamp; }
- bool GetUTurnsDefault() const override final { return m_profile_properties.allow_u_turn_at_via; }
+ bool GetContinueStraightDefault() const override final { return m_profile_properties.continue_straight_at_waypoint; }
};
}
}
diff --git a/include/engine/datafacade/shared_datafacade.hpp b/include/engine/datafacade/shared_datafacade.hpp
index dbb14bb..bd70e83 100644
--- a/include/engine/datafacade/shared_datafacade.hpp
+++ b/include/engine/datafacade/shared_datafacade.hpp
@@ -21,6 +21,7 @@
#include <cstddef>
#include <algorithm>
+#include <iterator>
#include <limits>
#include <memory>
#include <string>
@@ -708,7 +709,7 @@ class SharedDataFacade final : public BaseDataFacade
std::string GetTimestamp() const override final { return m_timestamp; }
- bool GetUTurnsDefault() const override final { return m_profile_properties->allow_u_turn_at_via; }
+ bool GetContinueStraightDefault() const override final { return m_profile_properties->continue_straight_at_waypoint; }
};
}
}
diff --git a/include/engine/douglas_peucker.hpp b/include/engine/douglas_peucker.hpp
index 468c6c7..e95d0cc 100644
--- a/include/engine/douglas_peucker.hpp
+++ b/include/engine/douglas_peucker.hpp
@@ -12,26 +12,47 @@ namespace engine
{
namespace detail
{
-const constexpr int DOUGLAS_PEUCKER_THRESHOLDS[19] = {
- 512440, // z0
- 256720, // z1
- 122560, // z2
- 56780, // z3
- 28800, // z4
- 14400, // z5
- 7200, // z6
- 3200, // z7
- 2400, // z8
- 1000, // z9
- 600, // z10
- 120, // z11
- 60, // z12
- 45, // z13
- 36, // z14
- 20, // z15
- 8, // z16
- 6, // z17
- 4, // z18
+
+// This is derived from the following formular:
+// x = b * (1 + lon/180) => dx = b * dlon/180
+// y = b * (1 - lat/180) => dy = b * dlat/180
+// dx^2 + dy^2 < min_pixel^2
+// => dlon^2 + dlat^2 < min_pixel^2 / b^2 * 180^2
+inline std::vector<std::uint64_t> generateThreshold(double min_pixel, unsigned number_of_zoomlevels)
+{
+ std::vector<std::uint64_t> thresholds(number_of_zoomlevels);
+ for (unsigned zoom = 0; zoom < number_of_zoomlevels; ++zoom)
+ {
+ const double shift = (1u << zoom) * 256;
+ const double b = shift / 2.0;
+ const double pixel_to_deg = 180. / b;
+ const std::uint64_t min_deg = min_pixel * pixel_to_deg * COORDINATE_PRECISION;
+ thresholds[zoom] = min_deg * min_deg;
+ }
+
+ return thresholds;
+}
+
+const constexpr std::uint64_t DOUGLAS_PEUCKER_THRESHOLDS[19] = {
+ 49438476562500, // z0
+ 12359619140625, // z1
+ 3089903027344, // z2
+ 772475756836, // z3
+ 193118939209, // z4
+ 48279515076, // z5
+ 12069878769, // z6
+ 3017414761, // z7
+ 754326225, // z8
+ 188567824, // z9
+ 47141956, // z10
+ 11785489, // z11
+ 2944656, // z12
+ 736164, // z13
+ 184041, // z14
+ 45796, // z15
+ 11449, // z16
+ 2809, // z17
+ 676, // z18
};
const constexpr auto DOUGLAS_PEUCKER_THRESHOLDS_SIZE =
diff --git a/include/engine/geospatial_query.hpp b/include/engine/geospatial_query.hpp
index e880139..d2e90b8 100644
--- a/include/engine/geospatial_query.hpp
+++ b/include/engine/geospatial_query.hpp
@@ -6,6 +6,7 @@
#include "engine/phantom_node.hpp"
#include "util/bearing.hpp"
#include "util/rectangle.hpp"
+#include "util/web_mercator.hpp"
#include "osrm/coordinate.hpp"
@@ -424,10 +425,11 @@ template <typename RTreeT, typename DataFacadeT> class GeospatialQuery
BOOST_ASSERT(segment.data.reverse_segment_id.id != SPECIAL_SEGMENTID ||
!segment.data.reverse_segment_id.enabled);
- Coordinate wsg84_coordinate = util::coordinate_calculation::mercator::toWGS84(
- segment.fixed_projected_coordinate);
+ Coordinate wsg84_coordinate =
+ util::web_mercator::toWGS84(segment.fixed_projected_coordinate);
- return util::coordinate_calculation::haversineDistance(input_coordinate, wsg84_coordinate) > max_distance;
+ return util::coordinate_calculation::haversineDistance(input_coordinate, wsg84_coordinate) >
+ max_distance;
}
std::pair<bool, bool> checkSegmentBearing(const CandidateSegment &segment,
diff --git a/include/engine/guidance/assemble_leg.hpp b/include/engine/guidance/assemble_leg.hpp
index bf34d74..b8d3dfe 100644
--- a/include/engine/guidance/assemble_leg.hpp
+++ b/include/engine/guidance/assemble_leg.hpp
@@ -1,20 +1,20 @@
#ifndef ENGINE_GUIDANCE_ASSEMBLE_LEG_HPP_
#define ENGINE_GUIDANCE_ASSEMBLE_LEG_HPP_
+#include "engine/guidance/leg_geometry.hpp"
#include "engine/guidance/route_leg.hpp"
#include "engine/guidance/route_step.hpp"
-#include "engine/guidance/leg_geometry.hpp"
#include "engine/internal_route_result.hpp"
#include <cstddef>
#include <cstdint>
-#include <vector>
+#include <algorithm>
#include <array>
+#include <numeric>
#include <string>
#include <utility>
-#include <numeric>
-#include <algorithm>
+#include <vector>
namespace osrm
{
@@ -22,86 +22,12 @@ namespace engine
{
namespace guidance
{
-namespace detail
-{
-const constexpr std::size_t MAX_USED_SEGMENTS = 2;
-struct NamedSegment
-{
- double duration;
- std::uint32_t position;
- std::uint32_t name_id;
-};
-template <std::size_t SegmentNumber>
-std::array<std::uint32_t, SegmentNumber> summarizeRoute(const std::vector<PathData> &route_data)
-{
- // merges segments with same name id
- const auto collapse_segments = [](std::vector<NamedSegment> &segments)
- {
- auto out = segments.begin();
- auto end = segments.end();
- for (auto in = segments.begin(); in != end; ++in)
- {
- if (in->name_id == out->name_id)
- {
- out->duration += in->duration;
- }
- else
- {
- ++out;
- BOOST_ASSERT(out != end);
- *out = *in;
- }
- }
- return out;
- };
-
- std::vector<NamedSegment> segments(route_data.size());
- std::uint32_t index = 0;
- std::transform(
- route_data.begin(), route_data.end(), segments.begin(), [&index](const PathData &point)
- {
- return NamedSegment{point.duration_until_turn / 10.0, index++, point.name_id};
- });
- // this makes sure that the segment with the lowest position comes first
- std::sort(segments.begin(), segments.end(), [](const NamedSegment &lhs, const NamedSegment &rhs)
- {
- return lhs.name_id < rhs.name_id ||
- (lhs.name_id == rhs.name_id && lhs.position < rhs.position);
- });
- auto new_end = collapse_segments(segments);
- segments.resize(new_end - segments.begin());
- // sort descending
- std::sort(segments.begin(), segments.end(), [](const NamedSegment &lhs, const NamedSegment &rhs)
- {
- return lhs.duration > rhs.duration;
- });
-
- // make sure the segments are sorted by position
- segments.resize(std::min(segments.size(), SegmentNumber));
- std::sort(segments.begin(), segments.end(), [](const NamedSegment &lhs, const NamedSegment &rhs)
- {
- return lhs.position < rhs.position;
- });
-
- std::array<std::uint32_t, SegmentNumber> summary;
- std::fill(summary.begin(), summary.end(), 0);
- std::transform(segments.begin(), segments.end(), summary.begin(),
- [](const NamedSegment &segment)
- {
- return segment.name_id;
- });
- return summary;
-}
-}
-
-template <typename DataFacadeT>
-RouteLeg assembleLeg(const DataFacadeT &facade,
- const std::vector<PathData> &route_data,
- const LegGeometry &leg_geometry,
- const PhantomNode &source_node,
- const PhantomNode &target_node,
- const bool target_traversed_in_reverse)
+inline RouteLeg assembleLeg(const std::vector<PathData> &route_data,
+ const LegGeometry &leg_geometry,
+ const PhantomNode &source_node,
+ const PhantomNode &target_node,
+ const bool target_traversed_in_reverse)
{
const auto target_duration =
(target_traversed_in_reverse ? target_node.reverse_weight : target_node.forward_weight) /
@@ -110,8 +36,7 @@ RouteLeg assembleLeg(const DataFacadeT &facade,
auto distance = std::accumulate(leg_geometry.segment_distances.begin(),
leg_geometry.segment_distances.end(), 0.);
auto duration = std::accumulate(route_data.begin(), route_data.end(), 0.,
- [](const double sum, const PathData &data)
- {
+ [](const double sum, const PathData &data) {
return sum + data.duration_until_turn;
}) /
10.;
@@ -140,26 +65,12 @@ RouteLeg assembleLeg(const DataFacadeT &facade,
duration = duration + target_duration;
if (route_data.empty())
{
- duration -=
- (target_traversed_in_reverse ? source_node.reverse_weight : source_node.forward_weight) / 10;
+ duration -= (target_traversed_in_reverse ? source_node.reverse_weight
+ : source_node.forward_weight) /
+ 10.0;
}
- auto summary_array = detail::summarizeRoute<detail::MAX_USED_SEGMENTS>(route_data);
-
- BOOST_ASSERT(detail::MAX_USED_SEGMENTS > 0);
- BOOST_ASSERT(summary_array.begin() != summary_array.end());
- std::string summary =
- std::accumulate(std::next(summary_array.begin()), summary_array.end(),
- facade.GetNameForID(summary_array.front()),
- [&facade](std::string previous, const std::uint32_t name_id)
- {
- if (name_id != 0)
- {
- previous += ", " + facade.GetNameForID(name_id);
- }
- return previous;
- });
- return RouteLeg{duration, distance, summary, {}};
+ return RouteLeg{duration, distance, {}};
}
} // namespace guidance
diff --git a/include/engine/guidance/assemble_steps.hpp b/include/engine/guidance/assemble_steps.hpp
index c6d19ee..a32811a 100644
--- a/include/engine/guidance/assemble_steps.hpp
+++ b/include/engine/guidance/assemble_steps.hpp
@@ -1,20 +1,20 @@
#ifndef ENGINE_GUIDANCE_ASSEMBLE_STEPS_HPP_
#define ENGINE_GUIDANCE_ASSEMBLE_STEPS_HPP_
+#include "engine/guidance/leg_geometry.hpp"
#include "engine/guidance/route_step.hpp"
#include "engine/guidance/step_maneuver.hpp"
-#include "engine/guidance/leg_geometry.hpp"
#include "engine/guidance/toolkit.hpp"
-#include "extractor/guidance/turn_instruction.hpp"
#include "engine/internal_route_result.hpp"
#include "engine/phantom_node.hpp"
-#include "util/coordinate_calculation.hpp"
-#include "util/coordinate.hpp"
-#include "util/bearing.hpp"
+#include "extractor/guidance/turn_instruction.hpp"
#include "extractor/travel_mode.hpp"
+#include "util/bearing.hpp"
+#include "util/coordinate.hpp"
+#include "util/coordinate_calculation.hpp"
-#include <vector>
#include <boost/optional.hpp>
+#include <vector>
namespace osrm
{
@@ -44,6 +44,7 @@ std::vector<RouteStep> assembleSteps(const DataFacadeT &facade,
const bool target_traversed_in_reverse)
{
const double constexpr ZERO_DURATION = 0., ZERO_DISTANCE = 0.;
+ const constexpr char *NO_ROTARY_NAME = "";
const EdgeWeight source_duration =
source_traversed_in_reverse ? source_node.reverse_weight : source_node.forward_weight;
const auto source_mode = source_traversed_in_reverse ? source_node.backward_travel_mode
@@ -84,13 +85,9 @@ std::vector<RouteStep> assembleSteps(const DataFacadeT &facade,
BOOST_ASSERT(segment_duration >= 0);
const auto name = facade.GetNameForID(path_point.name_id);
const auto distance = leg_geometry.segment_distances[segment_index];
- steps.push_back(RouteStep{path_point.name_id,
- name,
- segment_duration / 10.0,
- distance,
- path_point.travel_mode,
- maneuver,
- leg_geometry.FrontIndex(segment_index),
+ steps.push_back(RouteStep{path_point.name_id, name, NO_ROTARY_NAME,
+ segment_duration / 10.0, distance, path_point.travel_mode,
+ maneuver, leg_geometry.FrontIndex(segment_index),
leg_geometry.BackIndex(segment_index) + 1});
maneuver = detail::stepManeuverFromGeometry(path_point.turn_instruction,
leg_geometry, segment_index);
@@ -101,12 +98,8 @@ std::vector<RouteStep> assembleSteps(const DataFacadeT &facade,
const auto distance = leg_geometry.segment_distances[segment_index];
const int duration = segment_duration + target_duration;
BOOST_ASSERT(duration >= 0);
- steps.push_back(RouteStep{target_node.name_id,
- facade.GetNameForID(target_node.name_id),
- duration / 10.,
- distance,
- target_mode,
- maneuver,
+ steps.push_back(RouteStep{target_node.name_id, facade.GetNameForID(target_node.name_id),
+ NO_ROTARY_NAME, duration / 10., distance, target_mode, maneuver,
leg_geometry.FrontIndex(segment_index),
leg_geometry.BackIndex(segment_index) + 1});
}
@@ -124,13 +117,10 @@ std::vector<RouteStep> assembleSteps(const DataFacadeT &facade,
int duration = target_duration - source_duration;
BOOST_ASSERT(duration >= 0);
- steps.push_back(RouteStep{source_node.name_id,
- facade.GetNameForID(source_node.name_id),
- duration / 10.,
- leg_geometry.segment_distances[segment_index],
- source_mode,
- std::move(maneuver),
- leg_geometry.FrontIndex(segment_index),
+ steps.push_back(RouteStep{source_node.name_id, facade.GetNameForID(source_node.name_id),
+ NO_ROTARY_NAME, duration / 10.,
+ leg_geometry.segment_distances[segment_index], source_mode,
+ std::move(maneuver), leg_geometry.FrontIndex(segment_index),
leg_geometry.BackIndex(segment_index) + 1});
}
@@ -138,13 +128,11 @@ std::vector<RouteStep> assembleSteps(const DataFacadeT &facade,
// This step has length zero, the only reason we need it is the target location
auto final_maneuver = detail::stepManeuverFromGeometry(
extractor::guidance::TurnInstruction::NO_TURN(), WaypointType::Arrive, leg_geometry);
- steps.push_back(RouteStep{target_node.name_id,
- facade.GetNameForID(target_node.name_id),
- ZERO_DURATION,
- ZERO_DISTANCE,
- target_mode,
- final_maneuver,
- leg_geometry.locations.size(),
+
+ BOOST_ASSERT(!leg_geometry.locations.empty());
+ steps.push_back(RouteStep{target_node.name_id, facade.GetNameForID(target_node.name_id),
+ NO_ROTARY_NAME, ZERO_DURATION, ZERO_DISTANCE, target_mode,
+ final_maneuver, leg_geometry.locations.size()-1,
leg_geometry.locations.size()});
return steps;
diff --git a/include/engine/guidance/route_leg.hpp b/include/engine/guidance/route_leg.hpp
index 5ecca4f..f3b8de1 100644
--- a/include/engine/guidance/route_leg.hpp
+++ b/include/engine/guidance/route_leg.hpp
@@ -3,9 +3,6 @@
#include "engine/guidance/route_step.hpp"
-#include <boost/optional.hpp>
-
-#include <string>
#include <vector>
namespace osrm
@@ -19,7 +16,6 @@ struct RouteLeg
{
double duration;
double distance;
- std::string summary;
std::vector<RouteStep> steps;
};
}
diff --git a/include/engine/guidance/route_step.hpp b/include/engine/guidance/route_step.hpp
index 1a53579..d5950a6 100644
--- a/include/engine/guidance/route_step.hpp
+++ b/include/engine/guidance/route_step.hpp
@@ -1,8 +1,8 @@
#ifndef ROUTE_STEP_HPP
#define ROUTE_STEP_HPP
-#include "extractor/travel_mode.hpp"
#include "engine/guidance/step_maneuver.hpp"
+#include "extractor/travel_mode.hpp"
#include <cstddef>
@@ -25,6 +25,7 @@ struct RouteStep
{
unsigned name_id;
std::string name;
+ std::string rotary_name;
double duration;
double distance;
extractor::TravelMode mode;
diff --git a/include/engine/hint.hpp b/include/engine/hint.hpp
index 0ecaff6..56dfbc4 100644
--- a/include/engine/hint.hpp
+++ b/include/engine/hint.hpp
@@ -70,8 +70,8 @@ static_assert(ENCODED_HINT_SIZE / 4 * 3 >= sizeof(Hint),
"ENCODED_HINT_SIZE does not match size of Hint");
#else
// PhantomNode is bigger under windows because MSVC does not support bit packing
-static_assert(sizeof(Hint) == 64 + 4, "Hint is bigger than expected");
-constexpr std::size_t ENCODED_HINT_SIZE = 92;
+static_assert(sizeof(Hint) == 72 + 4, "Hint is bigger than expected");
+constexpr std::size_t ENCODED_HINT_SIZE = 104;
static_assert(ENCODED_HINT_SIZE / 4 * 3 >= sizeof(Hint),
"ENCODED_HINT_SIZE does not match size of Hint");
#endif
diff --git a/include/engine/map_matching/hidden_markov_model.hpp b/include/engine/map_matching/hidden_markov_model.hpp
index 303a835..9b36343 100644
--- a/include/engine/map_matching/hidden_markov_model.hpp
+++ b/include/engine/map_matching/hidden_markov_model.hpp
@@ -69,7 +69,7 @@ template <class CandidateLists> struct HiddenMarkovModel
path_distances.resize(candidates_list.size());
pruned.resize(candidates_list.size());
breakage.resize(candidates_list.size());
- for (const auto i : util::irange<std::size_t>(0u, candidates_list.size()))
+ for (const auto i : util::irange<std::size_t>(0UL, candidates_list.size()))
{
const auto &num_candidates = candidates_list[i].size();
// add empty vectors
@@ -107,7 +107,7 @@ template <class CandidateLists> struct HiddenMarkovModel
{
BOOST_ASSERT(initial_timestamp < num_points);
- for (const auto s : util::irange<std::size_t>(0u, viterbi[initial_timestamp].size()))
+ for (const auto s : util::irange<std::size_t>(0UL, viterbi[initial_timestamp].size()))
{
viterbi[initial_timestamp][s] = emission_log_probabilities[initial_timestamp][s];
parents[initial_timestamp][s] = std::make_pair(initial_timestamp, s);
diff --git a/include/engine/phantom_node.hpp b/include/engine/phantom_node.hpp
index 244276c..88724b1 100644
--- a/include/engine/phantom_node.hpp
+++ b/include/engine/phantom_node.hpp
@@ -168,7 +168,7 @@ struct PhantomNode
#ifndef _MSC_VER
static_assert(sizeof(PhantomNode) == 60, "PhantomNode has more padding then expected");
#else
-static_assert(sizeof(PhantomNode) == 64, "PhantomNode has more padding then expected");
+static_assert(sizeof(PhantomNode) == 72, "PhantomNode has more padding then expected");
#endif
using PhantomNodePair = std::pair<PhantomNode, PhantomNode>;
diff --git a/include/engine/plugins/plugin_base.hpp b/include/engine/plugins/plugin_base.hpp
index aec9dd0..e030ff8 100644
--- a/include/engine/plugins/plugin_base.hpp
+++ b/include/engine/plugins/plugin_base.hpp
@@ -12,6 +12,7 @@
#include "util/integer_range.hpp"
#include <algorithm>
+#include <iterator>
#include <string>
#include <vector>
@@ -122,7 +123,7 @@ class BasePlugin
const bool use_hints = !parameters.hints.empty();
const bool use_bearings = !parameters.bearings.empty();
- for (const auto i : util::irange<std::size_t>(0, parameters.coordinates.size()))
+ for (const auto i : util::irange<std::size_t>(0UL, parameters.coordinates.size()))
{
if (use_hints && parameters.hints[i] &&
parameters.hints[i]->IsValid(parameters.coordinates[i], facade))
@@ -161,7 +162,7 @@ class BasePlugin
const bool use_radiuses = !parameters.radiuses.empty();
BOOST_ASSERT(parameters.IsValid());
- for (const auto i : util::irange<std::size_t>(0, parameters.coordinates.size()))
+ for (const auto i : util::irange<std::size_t>(0UL, parameters.coordinates.size()))
{
if (use_hints && parameters.hints[i] &&
parameters.hints[i]->IsValid(parameters.coordinates[i], facade))
@@ -221,7 +222,7 @@ class BasePlugin
const bool use_radiuses = !parameters.radiuses.empty();
BOOST_ASSERT(parameters.IsValid());
- for (const auto i : util::irange<std::size_t>(0, parameters.coordinates.size()))
+ for (const auto i : util::irange<std::size_t>(0UL, parameters.coordinates.size()))
{
if (use_hints && parameters.hints[i] &&
parameters.hints[i]->IsValid(parameters.coordinates[i], facade))
diff --git a/include/engine/routing_algorithms/alternative_path.hpp b/include/engine/routing_algorithms/alternative_path.hpp
index 8dcc123..493d62f 100644
--- a/include/engine/routing_algorithms/alternative_path.hpp
+++ b/include/engine/routing_algorithms/alternative_path.hpp
@@ -84,19 +84,25 @@ class AlternativeRouting final
int upper_bound_to_shortest_path_distance = INVALID_EDGE_WEIGHT;
NodeID middle_node = SPECIAL_NODEID;
const EdgeWeight min_edge_offset =
- std::min(phantom_node_pair.source_phantom.forward_segment_id.enabled ? -phantom_node_pair.source_phantom.GetForwardWeightPlusOffset() : 0,
- phantom_node_pair.source_phantom.reverse_segment_id.enabled ? -phantom_node_pair.source_phantom.GetReverseWeightPlusOffset() : 0);
+ std::min(phantom_node_pair.source_phantom.forward_segment_id.enabled
+ ? -phantom_node_pair.source_phantom.GetForwardWeightPlusOffset()
+ : 0,
+ phantom_node_pair.source_phantom.reverse_segment_id.enabled
+ ? -phantom_node_pair.source_phantom.GetReverseWeightPlusOffset()
+ : 0);
if (phantom_node_pair.source_phantom.forward_segment_id.enabled)
{
- BOOST_ASSERT(phantom_node_pair.source_phantom.forward_segment_id.id != SPECIAL_SEGMENTID);
+ BOOST_ASSERT(phantom_node_pair.source_phantom.forward_segment_id.id !=
+ SPECIAL_SEGMENTID);
forward_heap1.Insert(phantom_node_pair.source_phantom.forward_segment_id.id,
-phantom_node_pair.source_phantom.GetForwardWeightPlusOffset(),
phantom_node_pair.source_phantom.forward_segment_id.id);
}
if (phantom_node_pair.source_phantom.reverse_segment_id.enabled)
{
- BOOST_ASSERT(phantom_node_pair.source_phantom.reverse_segment_id.id != SPECIAL_SEGMENTID);
+ BOOST_ASSERT(phantom_node_pair.source_phantom.reverse_segment_id.id !=
+ SPECIAL_SEGMENTID);
forward_heap1.Insert(phantom_node_pair.source_phantom.reverse_segment_id.id,
-phantom_node_pair.source_phantom.GetReverseWeightPlusOffset(),
phantom_node_pair.source_phantom.reverse_segment_id.id);
@@ -104,14 +110,16 @@ class AlternativeRouting final
if (phantom_node_pair.target_phantom.forward_segment_id.enabled)
{
- BOOST_ASSERT(phantom_node_pair.target_phantom.forward_segment_id.id != SPECIAL_SEGMENTID);
+ BOOST_ASSERT(phantom_node_pair.target_phantom.forward_segment_id.id !=
+ SPECIAL_SEGMENTID);
reverse_heap1.Insert(phantom_node_pair.target_phantom.forward_segment_id.id,
phantom_node_pair.target_phantom.GetForwardWeightPlusOffset(),
phantom_node_pair.target_phantom.forward_segment_id.id);
}
if (phantom_node_pair.target_phantom.reverse_segment_id.enabled)
{
- BOOST_ASSERT(phantom_node_pair.target_phantom.reverse_segment_id.id != SPECIAL_SEGMENTID);
+ BOOST_ASSERT(phantom_node_pair.target_phantom.reverse_segment_id.id !=
+ SPECIAL_SEGMENTID);
reverse_heap1.Insert(phantom_node_pair.target_phantom.reverse_segment_id.id,
phantom_node_pair.target_phantom.GetReverseWeightPlusOffset(),
phantom_node_pair.target_phantom.reverse_segment_id.id);
@@ -308,9 +316,11 @@ class AlternativeRouting final
BOOST_ASSERT(!packed_shortest_path.empty());
raw_route_data.unpacked_path_segments.resize(1);
raw_route_data.source_traversed_in_reverse.push_back(
- (packed_shortest_path.front() != phantom_node_pair.source_phantom.forward_segment_id.id));
+ (packed_shortest_path.front() !=
+ phantom_node_pair.source_phantom.forward_segment_id.id));
raw_route_data.target_traversed_in_reverse.push_back(
- (packed_shortest_path.back() != phantom_node_pair.target_phantom.forward_segment_id.id));
+ (packed_shortest_path.back() !=
+ phantom_node_pair.target_phantom.forward_segment_id.id));
super::UnpackPath(
// -- packed input
@@ -329,10 +339,12 @@ class AlternativeRouting final
RetrievePackedAlternatePath(forward_heap1, reverse_heap1, forward_heap2, reverse_heap2,
s_v_middle, v_t_middle, packed_alternate_path);
- raw_route_data.alt_source_traversed_in_reverse.push_back((
- packed_alternate_path.front() != phantom_node_pair.source_phantom.forward_segment_id.id));
+ raw_route_data.alt_source_traversed_in_reverse.push_back(
+ (packed_alternate_path.front() !=
+ phantom_node_pair.source_phantom.forward_segment_id.id));
raw_route_data.alt_target_traversed_in_reverse.push_back(
- (packed_alternate_path.back() != phantom_node_pair.target_phantom.forward_segment_id.id));
+ (packed_alternate_path.back() !=
+ phantom_node_pair.target_phantom.forward_segment_id.id));
// unpack the alternate path
super::UnpackPath(packed_alternate_path.begin(), packed_alternate_path.end(),
@@ -429,9 +441,9 @@ class AlternativeRouting final
// partial unpacking, compute sharing
// First partially unpack s-->v until paths deviate, note length of common path.
- const int64_t s_v_min_path_size =
- static_cast<int64_t>(std::min(packed_s_v_path.size(), packed_shortest_path.size())) - 1;
- for (const int64_t current_node : util::irange<int64_t>(0, s_v_min_path_size))
+ const auto s_v_min_path_size =
+ std::min(packed_s_v_path.size(), packed_shortest_path.size()) - 1;
+ for (const auto current_node : util::irange<std::size_t>(0UL, s_v_min_path_size))
{
if (packed_s_v_path[current_node] == packed_shortest_path[current_node] &&
packed_s_v_path[current_node + 1] == packed_shortest_path[current_node + 1])
diff --git a/include/engine/routing_algorithms/map_matching.hpp b/include/engine/routing_algorithms/map_matching.hpp
index 7d8b04e..0b1020a 100644
--- a/include/engine/routing_algorithms/map_matching.hpp
+++ b/include/engine/routing_algorithms/map_matching.hpp
@@ -244,14 +244,14 @@ class MapMatching final : public BasicRoutingInterface<DataFacadeT, MapMatching<
((haversine_distance + max_distance_delta) * 0.25) * 10;
// compute d_t for this timestamp and the next one
- for (const auto s : util::irange<std::size_t>(0u, prev_viterbi.size()))
+ for (const auto s : util::irange<std::size_t>(0UL, prev_viterbi.size()))
{
if (prev_pruned[s])
{
continue;
}
- for (const auto s_prime : util::irange<std::size_t>(0u, current_viterbi.size()))
+ for (const auto s_prime : util::irange<std::size_t>(0UL, current_viterbi.size()))
{
const double emission_pr = emission_log_probabilities[t][s_prime];
double new_value = prev_viterbi[s] + emission_pr;
diff --git a/include/engine/routing_algorithms/shortest_path.hpp b/include/engine/routing_algorithms/shortest_path.hpp
index 9720931..7b8fd7c 100644
--- a/include/engine/routing_algorithms/shortest_path.hpp
+++ b/include/engine/routing_algorithms/shortest_path.hpp
@@ -227,7 +227,7 @@ class ShortestPathRouting final
raw_route_data.shortest_path_length = shortest_path_length;
- for (const auto current_leg : util::irange<std::size_t>(0, packed_leg_begin.size() - 1))
+ for (const auto current_leg : util::irange<std::size_t>(0UL, packed_leg_begin.size() - 1))
{
auto leg_begin = total_packed_path.begin() + packed_leg_begin[current_leg];
auto leg_end = total_packed_path.begin() + packed_leg_begin[current_leg + 1];
@@ -245,10 +245,10 @@ class ShortestPathRouting final
}
void operator()(const std::vector<PhantomNodes> &phantom_nodes_vector,
- const boost::optional<bool> uturns,
+ const boost::optional<bool> continue_straight_at_waypoint,
InternalRouteResult &raw_route_data) const
{
- const bool allow_u_turn_at_via = uturns ? *uturns : super::facade->GetUTurnsDefault();
+ const bool allow_uturn_at_waypoint = !(continue_straight_at_waypoint ? *continue_straight_at_waypoint : super::facade->GetContinueStraightDefault());
engine_working_data.InitializeOrClearFirstThreadLocalStorage(
super::facade->GetNumberOfNodes());
@@ -299,7 +299,7 @@ class ShortestPathRouting final
if (search_to_reverse_node || search_to_forward_node)
{
- if (allow_u_turn_at_via)
+ if (allow_uturn_at_waypoint)
{
SearchWithUTurn(forward_heap, reverse_heap, forward_core_heap,
reverse_core_heap, search_from_forward_node,
@@ -309,7 +309,7 @@ class ShortestPathRouting final
new_total_distance_to_forward, packed_leg_to_forward);
// if only the reverse node is valid (e.g. when using the match plugin) we
// actually need to move
- if (target_phantom.forward_segment_id.enabled)
+ if (!target_phantom.forward_segment_id.enabled)
{
BOOST_ASSERT(target_phantom.reverse_segment_id.enabled);
new_total_distance_to_reverse = new_total_distance_to_forward;
diff --git a/include/extractor/guidance/constants.hpp b/include/extractor/guidance/constants.hpp
new file mode 100644
index 0000000..0418682
--- /dev/null
+++ b/include/extractor/guidance/constants.hpp
@@ -0,0 +1,32 @@
+#ifndef OSRM_EXTRACTOR_GUIDANCE_CONSTANTS_HPP_
+#define OSRM_EXTRACTOR_GUIDANCE_CONSTANTS_HPP_
+
+namespace osrm
+{
+namespace extractor
+{
+namespace guidance
+{
+
+const bool constexpr INVERT = true;
+
+// what angle is interpreted as going straight
+const double constexpr STRAIGHT_ANGLE = 180.;
+// if a turn deviates this much from going straight, it will be kept straight
+const double constexpr MAXIMAL_ALLOWED_NO_TURN_DEVIATION = 3.;
+// angle that lies between two nearly indistinguishable roads
+const double constexpr NARROW_TURN_ANGLE = 40.;
+const double constexpr GROUP_ANGLE = 90;
+// angle difference that can be classified as straight, if its the only narrow turn
+const double constexpr FUZZY_ANGLE_DIFFERENCE = 15.;
+const double constexpr DISTINCTION_RATIO = 2;
+const unsigned constexpr INVALID_NAME_ID = 0;
+
+const double constexpr MAX_ROUNDABOUT_RADIUS = 15; // 30 m diameter as final distinction
+const double constexpr INCREASES_BY_FOURTY_PERCENT = 1.4;
+
+} // namespace guidance
+} // namespace extractor
+} // namespace osrm
+
+#endif // OSRM_EXTRACTOR_GUIDANCE_CONSTANTS_HPP_
diff --git a/include/extractor/guidance/intersection.hpp b/include/extractor/guidance/intersection.hpp
new file mode 100644
index 0000000..8b350e2
--- /dev/null
+++ b/include/extractor/guidance/intersection.hpp
@@ -0,0 +1,66 @@
+#ifndef OSRM_EXTRACTOR_GUIDANCE_INTERSECTION_HPP_
+#define OSRM_EXTRACTOR_GUIDANCE_INTERSECTION_HPP_
+
+#include <string>
+#include <vector>
+
+#include "extractor/guidance/turn_instruction.hpp"
+#include "util/typedefs.hpp" // EdgeID
+
+namespace osrm
+{
+namespace extractor
+{
+namespace guidance
+{
+
+// Every Turn Operation describes a way of switching onto a segment, indicated by an EdgeID. The
+// associated turn is described by an angle and an instruction that is used to announce it.
+// The Turn Operation indicates what is exposed to the outside of the turn analysis.
+struct TurnOperation final
+{
+ EdgeID eid;
+ double angle;
+ TurnInstruction instruction;
+};
+
+// A Connected Road is the internal representation of a potential turn. Internally, we require
+// full list of all connected roads to determine the outcome.
+// The reasoning behind is that even invalid turns can influence the perceived angles, or even
+// instructions themselves. An pososible example can be described like this:
+//
+// aaa(2)aa
+// a - bbbbb
+// aaa(1)aa
+//
+// will not be perceived as a turn from (1) -> b, and as a U-turn from (1) -> (2).
+// In addition, they can influence whether a turn is obvious or not. b->(2) would also be no
+// turn-operation,
+// but rather a name change.
+//
+// If this were a normal intersection with
+//
+// cccccccc
+// o bbbbb
+// aaaaaaaa
+//
+// We would perceive a->c as a sharp turn, a->b as a slight turn, and b->c as a slight turn.
+struct ConnectedRoad final
+{
+ ConnectedRoad(const TurnOperation turn, const bool entry_allowed = false);
+
+ // a turn may be relevant to good instructions, even if we cannot enter the road
+ bool entry_allowed;
+ TurnOperation turn;
+};
+
+// small helper function to print the content of a connected road
+std::string toString(const ConnectedRoad &road);
+
+typedef std::vector<ConnectedRoad> Intersection;
+
+} // namespace guidance
+} // namespace extractor
+} // namespace osrm
+
+#endif /*OSRM_EXTRACTOR_GUIDANCE_INTERSECTION_HPP_*/
diff --git a/include/extractor/guidance/intersection_generator.hpp b/include/extractor/guidance/intersection_generator.hpp
new file mode 100644
index 0000000..be99a71
--- /dev/null
+++ b/include/extractor/guidance/intersection_generator.hpp
@@ -0,0 +1,68 @@
+#ifndef OSRM_EXTRACTOR_GUIDANCE_INTERSECTION_GENERATOR_HPP_
+#define OSRM_EXTRACTOR_GUIDANCE_INTERSECTION_GENERATOR_HPP_
+
+#include "extractor/compressed_edge_container.hpp"
+#include "extractor/guidance/intersection.hpp"
+#include "extractor/query_node.hpp"
+#include "extractor/restriction_map.hpp"
+#include "util/node_based_graph.hpp"
+#include "util/typedefs.hpp"
+
+#include <unordered_set>
+#include <vector>
+
+namespace osrm
+{
+namespace extractor
+{
+namespace guidance
+{
+// The Intersection Generator is given a turn location and generates an intersection representation
+// from it. For this all turn possibilities are analysed.
+// We consider turn restrictions to indicate possible turns. U-turns are generated based on profile
+// decisions.
+
+class IntersectionGenerator
+{
+ public:
+ IntersectionGenerator(const util::NodeBasedDynamicGraph &node_based_graph,
+ const RestrictionMap &restriction_map,
+ const std::unordered_set<NodeID> &barrier_nodes,
+ const std::vector<QueryNode> &node_info_list,
+ const CompressedEdgeContainer &compressed_edge_container);
+
+ Intersection operator()(const NodeID nid, const EdgeID via_eid) const;
+
+ private:
+ const util::NodeBasedDynamicGraph &node_based_graph;
+ const RestrictionMap &restriction_map;
+ const std::unordered_set<NodeID> &barrier_nodes;
+ const std::vector<QueryNode> &node_info_list;
+ const CompressedEdgeContainer &compressed_edge_container;
+
+ // Check for restrictions/barriers and generate a list of valid and invalid turns present at
+ // the
+ // node reached
+ // from `from_node` via `via_eid`
+ // The resulting candidates have to be analysed for their actual instructions later on.
+ Intersection getConnectedRoads(const NodeID from_node, const EdgeID via_eid) const;
+
+ // Merge segregated roads to omit invalid turns in favor of treating segregated roads as
+ // one.
+ // This function combines roads the following way:
+ //
+ // * *
+ // * is converted to *
+ // v ^ +
+ // v ^ +
+ //
+ // The treatment results in a straight turn angle of 180º rather than a turn angle of approx
+ // 160
+ Intersection mergeSegregatedRoads(Intersection intersection) const;
+};
+
+} // namespace guidance
+} // namespace extractor
+} // namespace osrm
+
+#endif /* OSRM_EXTRACTOR_GUIDANCE_INTERSECTION_GENERATOR_HPP_ */
diff --git a/include/extractor/guidance/intersection_handler.hpp b/include/extractor/guidance/intersection_handler.hpp
new file mode 100644
index 0000000..25d2f4a
--- /dev/null
+++ b/include/extractor/guidance/intersection_handler.hpp
@@ -0,0 +1,71 @@
+#ifndef OSRM_EXTRACTOR_GUIDANCE_INTERSECTION_HANDLER_HPP_
+#define OSRM_EXTRACTOR_GUIDANCE_INTERSECTION_HANDLER_HPP_
+
+#include "extractor/guidance/intersection.hpp"
+#include "extractor/query_node.hpp"
+
+#include "util/name_table.hpp"
+#include "util/node_based_graph.hpp"
+
+#include <cstddef>
+#include <vector>
+
+namespace osrm
+{
+namespace extractor
+{
+namespace guidance
+{
+
+// Intersection handlers deal with all issues related to intersections.
+// They assign appropriate turn operations to the TurnOperations.
+// This base class provides both the interface and implementations for
+// common functions.
+class IntersectionHandler
+{
+ public:
+ IntersectionHandler(const util::NodeBasedDynamicGraph &node_based_graph,
+ const std::vector<QueryNode> &node_info_list,
+ const util::NameTable &name_table);
+ virtual ~IntersectionHandler();
+
+ // check whether the handler can actually handle the intersection
+ virtual bool
+ canProcess(const NodeID nid, const EdgeID via_eid, const Intersection &intersection) const = 0;
+
+ // process the intersection
+ virtual Intersection
+ operator()(const NodeID nid, const EdgeID via_eid, Intersection intersection) const = 0;
+
+ protected:
+ const util::NodeBasedDynamicGraph &node_based_graph;
+ const std::vector<QueryNode> &node_info_list;
+ const util::NameTable &name_table;
+
+ // counts the number on allowed entry roads
+ std::size_t countValid(const Intersection &intersection) const;
+
+ // Decide on a basic turn types
+ TurnType findBasicTurnType(const EdgeID via_edge, const ConnectedRoad &candidate) const;
+
+ // Get the Instruction for an obvious turn
+ TurnInstruction getInstructionForObvious(const std::size_t number_of_candidates,
+ const EdgeID via_edge,
+ const bool through_street,
+ const ConnectedRoad &candidate) const;
+
+ // Treating potential forks
+ void assignFork(const EdgeID via_edge, ConnectedRoad &left, ConnectedRoad &right) const;
+ void assignFork(const EdgeID via_edge,
+ ConnectedRoad &left,
+ ConnectedRoad ¢er,
+ ConnectedRoad &right) const;
+
+ bool isThroughStreet(const std::size_t index, const Intersection &intersection) const;
+};
+
+} // namespace guidance
+} // namespace extractor
+} // namespace osrm
+
+#endif /*OSRM_EXTRACTOR_GUIDANCE_INTERSECTION_HANDLER_HPP_*/
diff --git a/include/extractor/guidance/motorway_handler.hpp b/include/extractor/guidance/motorway_handler.hpp
new file mode 100644
index 0000000..e3d9e34
--- /dev/null
+++ b/include/extractor/guidance/motorway_handler.hpp
@@ -0,0 +1,51 @@
+#ifndef OSRM_EXTRACTOR_GUIDANCE_MOTORWAY_HANDLER_HPP_
+#define OSRM_EXTRACTOR_GUIDANCE_MOTORWAY_HANDLER_HPP_
+
+#include "extractor/guidance/intersection_handler.hpp"
+#include "extractor/guidance/intersection.hpp"
+#include "extractor/query_node.hpp"
+
+#include "util/name_table.hpp"
+#include "util/node_based_graph.hpp"
+
+#include <vector>
+
+namespace osrm
+{
+namespace extractor
+{
+namespace guidance
+{
+
+// Intersection handlers deal with all issues related to intersections.
+// They assign appropriate turn operations to the TurnOperations.
+class MotorwayHandler : public IntersectionHandler
+{
+ public:
+ MotorwayHandler(const util::NodeBasedDynamicGraph &node_based_graph,
+ const std::vector<QueryNode> &node_info_list,
+ const util::NameTable &name_table);
+ ~MotorwayHandler() override final;
+
+ // check whether the handler can actually handle the intersection
+ bool canProcess(const NodeID nid,
+ const EdgeID via_eid,
+ const Intersection &intersection) const override final;
+
+ // process the intersection
+ Intersection operator()(const NodeID nid,
+ const EdgeID via_eid,
+ Intersection intersection) const override final;
+
+ private:
+ Intersection fromMotorway(const EdgeID via_edge, Intersection intersection) const;
+ Intersection fromRamp(const EdgeID via_edge, Intersection intersection) const;
+
+ Intersection fallback(Intersection intersection) const;
+};
+
+} // namespace guidance
+} // namespace extractor
+} // namespace osrm
+
+#endif /*OSRM_EXTRACTOR_GUIDANCE_MOTORWAY_HANDLER_HPP_*/
diff --git a/include/extractor/guidance/roundabout_handler.hpp b/include/extractor/guidance/roundabout_handler.hpp
new file mode 100644
index 0000000..6a48387
--- /dev/null
+++ b/include/extractor/guidance/roundabout_handler.hpp
@@ -0,0 +1,71 @@
+#ifndef OSRM_EXTRACTOR_GUIDANCE_ROUNDABOUT_HANDLER_HPP_
+#define OSRM_EXTRACTOR_GUIDANCE_ROUNDABOUT_HANDLER_HPP_
+
+#include "extractor/guidance/intersection.hpp"
+#include "extractor/guidance/intersection_handler.hpp"
+#include "extractor/query_node.hpp"
+
+#include "util/name_table.hpp"
+#include "util/node_based_graph.hpp"
+#include "util/typedefs.hpp"
+
+#include <utility>
+#include <vector>
+
+namespace osrm
+{
+namespace extractor
+{
+namespace guidance
+{
+
+namespace detail
+{
+struct RoundaboutFlags
+{
+ bool on_roundabout;
+ bool can_enter;
+ bool can_exit_separately;
+};
+} // namespace detail
+
+// The roundabout handler processes all roundabout related instructions.
+// It performs both the distinction between rotaries and roundabouts and
+// assigns appropriate entry/exit instructions.
+class RoundaboutHandler : public IntersectionHandler
+{
+ public:
+ RoundaboutHandler(const util::NodeBasedDynamicGraph &node_based_graph,
+ const std::vector<QueryNode> &node_info_list,
+ const util::NameTable &name_table);
+
+ ~RoundaboutHandler() override final;
+
+ // check whether the handler can actually handle the intersection
+ bool canProcess(const NodeID from_nid, const EdgeID via_eid, const Intersection &intersection) const override final;
+
+ // process the intersection
+ Intersection operator()(const NodeID from_nid, const EdgeID via_eid, Intersection intersection) const override final;
+
+ private:
+ detail::RoundaboutFlags getRoundaboutFlags(const NodeID from_nid, const EdgeID via_eid, const Intersection &intersection) const;
+
+ // decide whether we lookk at a roundabout or a rotary
+ bool isRotary(const NodeID nid) const;
+
+ // TODO handle bike/walk cases that allow crossing a roundabout!
+ // Processing of roundabouts
+ // Produces instructions to enter/exit a roundabout or to stay on it.
+ // Performs the distinction between roundabout and rotaries.
+ Intersection handleRoundabouts(const bool is_rotary,
+ const EdgeID via_edge,
+ const bool on_roundabout,
+ const bool can_exit_roundabout,
+ Intersection intersection) const;
+};
+
+} // namespace guidance
+} // namespace extractor
+} // namespace osrm
+
+#endif /*OSRM_EXTRACTOR_GUIDANCE_ROUNDABOUT_HANDLER_HPP_*/
diff --git a/include/extractor/guidance/toolkit.hpp b/include/extractor/guidance/toolkit.hpp
index 45ca897..35fd547 100644
--- a/include/extractor/guidance/toolkit.hpp
+++ b/include/extractor/guidance/toolkit.hpp
@@ -8,14 +8,14 @@
#include "extractor/compressed_edge_container.hpp"
#include "extractor/query_node.hpp"
-#include "extractor/guidance/discrete_angle.hpp"
#include "extractor/guidance/classification_data.hpp"
+#include "extractor/guidance/discrete_angle.hpp"
#include "extractor/guidance/turn_instruction.hpp"
#include <algorithm>
-#include <map>
#include <cmath>
#include <cstdint>
+#include <map>
#include <string>
namespace osrm
@@ -42,22 +42,21 @@ getCoordinateFromCompressedRange(util::Coordinate current_coordinate,
const util::Coordinate final_coordinate,
const std::vector<extractor::QueryNode> &query_nodes)
{
- const auto extractCoordinateFromNode = [](const extractor::QueryNode &node) -> util::Coordinate
- {
+ const auto extractCoordinateFromNode =
+ [](const extractor::QueryNode &node) -> util::Coordinate {
return {node.lon, node.lat};
};
double distance_to_current_coordinate = 0;
double distance_to_next_coordinate = 0;
// get the length that is missing from the current segment to reach DESIRED_SEGMENT_LENGTH
- const auto getFactor = [](const double first_distance, const double second_distance)
- {
+ const auto getFactor = [](const double first_distance, const double second_distance) {
BOOST_ASSERT(first_distance < detail::DESIRED_SEGMENT_LENGTH);
double segment_length = second_distance - first_distance;
BOOST_ASSERT(segment_length > 0);
BOOST_ASSERT(second_distance >= detail::DESIRED_SEGMENT_LENGTH);
double missing_distance = detail::DESIRED_SEGMENT_LENGTH - first_distance;
- return missing_distance / segment_length;
+ return std::max(0., std::min(missing_distance / segment_length, 1.0));
};
for (auto compressed_geometry_itr = compressed_geometry_begin;
@@ -85,7 +84,8 @@ getCoordinateFromCompressedRange(util::Coordinate current_coordinate,
util::coordinate_calculation::haversineDistance(current_coordinate, final_coordinate);
// reached point where coordinates switch between
- if (distance_to_next_coordinate >= detail::DESIRED_SEGMENT_LENGTH)
+ if (distance_to_current_coordinate < detail::DESIRED_SEGMENT_LENGTH &&
+ distance_to_next_coordinate >= detail::DESIRED_SEGMENT_LENGTH)
return util::coordinate_calculation::interpolateLinear(
getFactor(distance_to_current_coordinate, distance_to_next_coordinate),
current_coordinate, final_coordinate);
@@ -104,8 +104,8 @@ getRepresentativeCoordinate(const NodeID from_node,
const extractor::CompressedEdgeContainer &compressed_geometries,
const std::vector<extractor::QueryNode> &query_nodes)
{
- const auto extractCoordinateFromNode = [](const extractor::QueryNode &node) -> util::Coordinate
- {
+ const auto extractCoordinateFromNode =
+ [](const extractor::QueryNode &node) -> util::Coordinate {
return {node.lon, node.lat};
};
@@ -298,14 +298,10 @@ inline DirectionModifier getTurnDirection(const double angle)
// swaps left <-> right modifier types
inline DirectionModifier mirrorDirectionModifier(const DirectionModifier modifier)
{
- const constexpr DirectionModifier results[] = {DirectionModifier::UTurn,
- DirectionModifier::SharpLeft,
- DirectionModifier::Left,
- DirectionModifier::SlightLeft,
- DirectionModifier::Straight,
- DirectionModifier::SlightRight,
- DirectionModifier::Right,
- DirectionModifier::SharpRight};
+ const constexpr DirectionModifier results[] = {
+ DirectionModifier::UTurn, DirectionModifier::SharpLeft, DirectionModifier::Left,
+ DirectionModifier::SlightLeft, DirectionModifier::Straight, DirectionModifier::SlightRight,
+ DirectionModifier::Right, DirectionModifier::SharpRight};
return results[modifier];
}
@@ -345,13 +341,14 @@ inline bool requiresNameAnnounced(const std::string &from, const std::string &to
std::string to_ref;
// Split from the format "{name} ({ref})" -> name, ref
- auto split = [](const std::string &name, std::string &out_name, std::string &out_ref)
- {
+ auto split = [](const std::string &name, std::string &out_name, std::string &out_ref) {
const auto ref_begin = name.find_first_of('(');
if (ref_begin != std::string::npos)
{
- out_name = name.substr(0, ref_begin);
- out_ref = name.substr(ref_begin + 1, name.find_first_of(')') - 1);
+ if (ref_begin != 0)
+ out_name = name.substr(0, ref_begin - 1);
+ const auto ref_end = name.find_first_of(')');
+ out_ref = name.substr(ref_begin + 1, ref_end - ref_begin - 1);
}
else
{
@@ -363,35 +360,38 @@ inline bool requiresNameAnnounced(const std::string &from, const std::string &to
split(to, to_name, to_ref);
// check similarity of names
- auto names_are_empty = from_name.empty() && to_name.empty();
- auto names_are_equal = from_name == to_name;
- auto name_is_removed = !from_name.empty() && to_name.empty();
+ const auto names_are_empty = from_name.empty() && to_name.empty();
+ const auto names_are_equal = from_name == to_name;
+ const auto name_is_removed = !from_name.empty() && to_name.empty();
// references are contained in one another
- auto refs_are_empty = from_ref.empty() && to_ref.empty();
- auto ref_is_contained =
- !from_ref.empty() && !to_ref.empty() &&
+ const auto refs_are_empty = from_ref.empty() && to_ref.empty();
+ const auto ref_is_contained =
+ from_ref.empty() || to_ref.empty() ||
(from_ref.find(to_ref) != std::string::npos || to_ref.find(from_ref) != std::string::npos);
- auto ref_is_removed = !from_ref.empty() && to_ref.empty();
+ const auto ref_is_removed = !from_ref.empty() && to_ref.empty();
- auto obvious_change = ref_is_contained || names_are_equal ||
- (names_are_empty && refs_are_empty) || name_is_removed || ref_is_removed;
+ const auto obvious_change =
+ (names_are_empty && refs_are_empty) || (names_are_equal && ref_is_contained) ||
+ (names_are_equal && refs_are_empty) || name_is_removed || ref_is_removed;
return !obvious_change;
}
-inline int getPriority( const FunctionalRoadClass road_class )
+inline int getPriority(const FunctionalRoadClass road_class)
{
- //The road priorities indicate which roads can bee seen as more or less equal.
- //They are used in Fork-Discovery. Possibly should be moved to profiles post v5?
- //A fork can happen between road types that are at most 1 priority apart from each other
- const constexpr int road_priority[] = {10, 0, 10, 2, 10, 4, 10, 6, 10, 8, 10, 11, 10, 12, 10, 14};
+ // The road priorities indicate which roads can bee seen as more or less equal.
+ // They are used in Fork-Discovery. Possibly should be moved to profiles post v5?
+ // A fork can happen between road types that are at most 1 priority apart from each other
+ const constexpr int road_priority[] = {10, 0, 10, 2, 10, 4, 10, 6,
+ 10, 8, 10, 11, 10, 12, 10, 14};
return road_priority[static_cast<int>(road_class)];
}
inline bool canBeSeenAsFork(const FunctionalRoadClass first, const FunctionalRoadClass second)
{
// forks require similar road categories
- // Based on the priorities assigned above, we can set forks only if the road priorities match closely.
+ // Based on the priorities assigned above, we can set forks only if the road priorities match
+ // closely.
// Potentially we could include features like number of lanes here and others?
// Should also be moved to profiles
return std::abs(getPriority(first) - getPriority(second)) <= 1;
diff --git a/include/extractor/guidance/turn_analysis.hpp b/include/extractor/guidance/turn_analysis.hpp
index 538fabc..f52d1b2 100644
--- a/include/extractor/guidance/turn_analysis.hpp
+++ b/include/extractor/guidance/turn_analysis.hpp
@@ -1,20 +1,27 @@
#ifndef OSRM_EXTRACTOR_TURN_ANALYSIS
#define OSRM_EXTRACTOR_TURN_ANALYSIS
-#include "extractor/guidance/turn_classification.hpp"
+#include "extractor/compressed_edge_container.hpp"
+#include "extractor/guidance/intersection.hpp"
+#include "extractor/guidance/intersection_generator.hpp"
#include "extractor/guidance/toolkit.hpp"
+#include "extractor/guidance/turn_classification.hpp"
+#include "extractor/guidance/roundabout_handler.hpp"
+#include "extractor/guidance/motorway_handler.hpp"
+#include "extractor/guidance/turn_handler.hpp"
+#include "extractor/query_node.hpp"
#include "extractor/restriction_map.hpp"
-#include "extractor/compressed_edge_container.hpp"
#include "util/name_table.hpp"
+#include "util/node_based_graph.hpp"
#include <cstdint>
-#include <string>
-#include <vector>
#include <memory>
-#include <utility>
+#include <string>
#include <unordered_set>
+#include <utility>
+#include <vector>
namespace osrm
{
@@ -23,46 +30,6 @@ namespace extractor
namespace guidance
{
-// What is exposed to the outside
-struct TurnOperation final
-{
- EdgeID eid;
- double angle;
- TurnInstruction instruction;
-};
-
-// For the turn analysis, we require a full list of all connected roads to determine the outcome.
-// Invalid turns can influence the perceived angles
-//
-// aaa(2)aa
-// a - bbbbb
-// aaa(1)aa
-//
-// will not be perceived as a turn from (1) -> b, and as a U-turn from (1) -> (2).
-// In addition, they can influence whether a turn is obvious or not.
-struct ConnectedRoad final
-{
- ConnectedRoad(const TurnOperation turn, const bool entry_allowed = false);
-
- TurnOperation turn;
- bool entry_allowed; // a turn may be relevant to good instructions, even if we cannot take
- // the road
-
- std::string toString() const
- {
- std::string result = "[connection] ";
- result += std::to_string(turn.eid);
- result += " allows entry: ";
- result += std::to_string(entry_allowed);
- result += " angle: ";
- result += std::to_string(turn.angle);
- result += " instruction: ";
- result += std::to_string(static_cast<std::int32_t>(turn.instruction.type)) + " " +
- std::to_string(static_cast<std::int32_t>(turn.instruction.direction_modifier));
- return result;
- }
-};
-
class TurnAnalysis
{
@@ -79,120 +46,14 @@ class TurnAnalysis
private:
const util::NodeBasedDynamicGraph &node_based_graph;
- const std::vector<QueryNode> &node_info_list;
- const RestrictionMap &restriction_map;
- const std::unordered_set<NodeID> &barrier_nodes;
- const CompressedEdgeContainer &compressed_edge_container;
- const util::NameTable &name_table;
-
- // Check for restrictions/barriers and generate a list of valid and invalid turns present at
- // the
- // node reached
- // from `from_node` via `via_eid`
- // The resulting candidates have to be analysed for their actual instructions later on.
- std::vector<ConnectedRoad> getConnectedRoads(const NodeID from_node,
- const EdgeID via_eid) const;
-
- // Merge segregated roads to omit invalid turns in favor of treating segregated roads as
- // one.
- // This function combines roads the following way:
- //
- // * *
- // * is converted to *
- // v ^ +
- // v ^ +
- //
- // The treatment results in a straight turn angle of 180º rather than a turn angle of approx
- // 160
- std::vector<ConnectedRoad> mergeSegregatedRoads(std::vector<ConnectedRoad> intersection) const;
-
- // TODO distinguish roundabouts and rotaries
- // TODO handle bike/walk cases that allow crossing a roundabout!
-
- // Processing of roundabouts
- // Produces instructions to enter/exit a roundabout or to stay on it.
- // Performs the distinction between roundabout and rotaries.
- std::vector<ConnectedRoad> handleRoundabouts(const EdgeID via_edge,
- const bool on_roundabout,
- const bool can_exit_roundabout,
- std::vector<ConnectedRoad> intersection) const;
-
- // Indicates a Junction containing a motoryway
- bool isMotorwayJunction(const EdgeID via_edge,
- const std::vector<ConnectedRoad> &intersection) const;
-
- // Decide whether a turn is a turn or a ramp access
- TurnType findBasicTurnType(const EdgeID via_edge, const ConnectedRoad &candidate) const;
-
- // Get the Instruction for an obvious turn
- // Instruction will be a silent instruction
- TurnInstruction getInstructionForObvious(const std::size_t number_of_candidates,
- const EdgeID via_edge,
- const ConnectedRoad &candidate) const;
-
- // Helper Function that decides between NoTurn or NewName
- TurnInstruction
- noTurnOrNewName(const NodeID from, const EdgeID via_edge, const ConnectedRoad &candidate) const;
-
- // Basic Turn Handling
-
- // Dead end.
- std::vector<ConnectedRoad> handleOneWayTurn(std::vector<ConnectedRoad> intersection) const;
-
- // Mode Changes, new names...
- std::vector<ConnectedRoad> handleTwoWayTurn(const EdgeID via_edge,
- std::vector<ConnectedRoad> intersection) const;
-
- // Forks, T intersections and similar
- std::vector<ConnectedRoad> handleThreeWayTurn(const EdgeID via_edge,
- std::vector<ConnectedRoad> intersection) const;
-
- // Handling of turns larger then degree three
- std::vector<ConnectedRoad> handleComplexTurn(const EdgeID via_edge,
- std::vector<ConnectedRoad> intersection) const;
-
- // Any Junction containing motorways
- std::vector<ConnectedRoad> handleMotorwayJunction(
- const EdgeID via_edge, std::vector<ConnectedRoad> intersection) const;
-
- std::vector<ConnectedRoad> handleFromMotorway(const EdgeID via_edge,
- std::vector<ConnectedRoad> intersection) const;
-
- std::vector<ConnectedRoad> handleMotorwayRamp(const EdgeID via_edge,
- std::vector<ConnectedRoad> intersection) const;
+ const IntersectionGenerator intersection_generator;
+ const RoundaboutHandler roundabout_handler;
+ const MotorwayHandler motorway_handler;
+ const TurnHandler turn_handler;
// Utility function, setting basic turn types. Prepares for normal turn handling.
- std::vector<ConnectedRoad> setTurnTypes(const NodeID from,
- const EdgeID via_edge,
- std::vector<ConnectedRoad> intersection) const;
-
- // Assignment of specific turn types
- void assignFork(const EdgeID via_edge, ConnectedRoad &left, ConnectedRoad &right) const;
- void assignFork(const EdgeID via_edge,
- ConnectedRoad &left,
- ConnectedRoad ¢er,
- ConnectedRoad &right) const;
-
- void
- handleDistinctConflict(const EdgeID via_edge, ConnectedRoad &left, ConnectedRoad &right) const;
-
- // Type specific fallbacks
- std::vector<ConnectedRoad>
- fallbackTurnAssignmentMotorway(std::vector<ConnectedRoad> intersection) const;
-
- // Classification
- std::size_t findObviousTurn(const EdgeID via_edge,
- const std::vector<ConnectedRoad> &intersection) const;
- std::pair<std::size_t, std::size_t>
- findFork(const std::vector<ConnectedRoad> &intersection) const;
-
- std::vector<ConnectedRoad> assignLeftTurns(const EdgeID via_edge,
- std::vector<ConnectedRoad> intersection,
- const std::size_t starting_at) const;
- std::vector<ConnectedRoad> assignRightTurns(const EdgeID via_edge,
- std::vector<ConnectedRoad> intersection,
- const std::size_t up_to) const;
-
+ Intersection
+ setTurnTypes(const NodeID from, const EdgeID via_edge, Intersection intersection) const;
}; // class TurnAnalysis
} // namespace guidance
diff --git a/include/extractor/guidance/turn_handler.hpp b/include/extractor/guidance/turn_handler.hpp
new file mode 100644
index 0000000..3420aa7
--- /dev/null
+++ b/include/extractor/guidance/turn_handler.hpp
@@ -0,0 +1,74 @@
+#ifndef OSRM_EXTRACTOR_GUIDANCE_TURN_HANDLER_HPP_
+#define OSRM_EXTRACTOR_GUIDANCE_TURN_HANDLER_HPP_
+
+#include "extractor/guidance/intersection_handler.hpp"
+#include "extractor/guidance/intersection.hpp"
+#include "extractor/query_node.hpp"
+
+#include "util/name_table.hpp"
+#include "util/node_based_graph.hpp"
+
+#include <cstddef>
+#include <vector>
+#include <utility>
+
+namespace osrm
+{
+namespace extractor
+{
+namespace guidance
+{
+
+// Intersection handlers deal with all issues related to intersections.
+// They assign appropriate turn operations to the TurnOperations.
+class TurnHandler : public IntersectionHandler
+{
+ public:
+ TurnHandler(const util::NodeBasedDynamicGraph &node_based_graph,
+ const std::vector<QueryNode> &node_info_list,
+ const util::NameTable &name_table);
+ ~TurnHandler() override final;
+
+ // check whether the handler can actually handle the intersection
+ bool canProcess(const NodeID nid,
+ const EdgeID via_eid,
+ const Intersection &intersection) const override final;
+
+ // process the intersection
+ Intersection operator()(const NodeID nid,
+ const EdgeID via_eid,
+ Intersection intersection) const override final;
+
+ private:
+ // Dead end.
+ Intersection handleOneWayTurn(Intersection intersection) const;
+
+ // Mode Changes, new names...
+ Intersection handleTwoWayTurn(const EdgeID via_edge, Intersection intersection) const;
+
+ // Forks, T intersections and similar
+ Intersection handleThreeWayTurn(const EdgeID via_edge, Intersection intersection) const;
+
+ // Handling of turns larger then degree three
+ Intersection handleComplexTurn(const EdgeID via_edge, Intersection intersection) const;
+
+ void
+ handleDistinctConflict(const EdgeID via_edge, ConnectedRoad &left, ConnectedRoad &right) const;
+
+ // Classification
+ std::size_t findObviousTurn(const EdgeID via_edge, const Intersection &intersection) const;
+ std::pair<std::size_t, std::size_t> findFork(const Intersection &intersection) const;
+
+ Intersection assignLeftTurns(const EdgeID via_edge,
+ Intersection intersection,
+ const std::size_t starting_at) const;
+ Intersection assignRightTurns(const EdgeID via_edge,
+ Intersection intersection,
+ const std::size_t up_to) const;
+};
+
+} // namespace guidance
+} // namespace extractor
+} // namespace osrm
+
+#endif /*OSRM_EXTRACTOR_GUIDANCE_TURN_HANDLER_HPP_*/
diff --git a/include/extractor/guidance/turn_instruction.hpp b/include/extractor/guidance/turn_instruction.hpp
index da3da62..d96c007 100644
--- a/include/extractor/guidance/turn_instruction.hpp
+++ b/include/extractor/guidance/turn_instruction.hpp
@@ -89,24 +89,32 @@ struct TurnInstruction
return TurnInstruction(TurnType::NoTurn, DirectionModifier::UTurn);
}
- static TurnInstruction REMAIN_ROUNDABOUT(const DirectionModifier modifier)
+ static TurnInstruction REMAIN_ROUNDABOUT(bool is_rotary, const DirectionModifier modifier)
{
+ (void)is_rotary; // staying does not require a different instruction at the moment
return TurnInstruction(TurnType::StayOnRoundabout, modifier);
}
- static TurnInstruction ENTER_ROUNDABOUT(const DirectionModifier modifier)
+ static TurnInstruction ENTER_ROUNDABOUT(bool is_rotary, const DirectionModifier modifier)
{
- return TurnInstruction(TurnType::EnterRoundabout, modifier);
+ return {is_rotary ? TurnType::EnterRotary : TurnType::EnterRoundabout, modifier};
}
- static TurnInstruction EXIT_ROUNDABOUT(const DirectionModifier modifier)
+ static TurnInstruction EXIT_ROUNDABOUT(bool is_rotary, const DirectionModifier modifier)
{
- return TurnInstruction(TurnType::ExitRoundabout, modifier);
+ return {is_rotary ? TurnType::ExitRotary : TurnType::ExitRoundabout, modifier};
+ }
+
+ static TurnInstruction ENTER_AND_EXIT_ROUNDABOUT(bool is_rotary,
+ const DirectionModifier modifier)
+ {
+ return {is_rotary ? TurnType::EnterAndExitRotary : TurnType::EnterAndExitRoundabout,
+ modifier};
}
static TurnInstruction SUPPRESSED(const DirectionModifier modifier)
{
- return TurnInstruction{TurnType::Suppressed, modifier};
+ return {TurnType::Suppressed, modifier};
}
};
diff --git a/include/extractor/profile_properties.hpp b/include/extractor/profile_properties.hpp
index 859034c..7976875 100644
--- a/include/extractor/profile_properties.hpp
+++ b/include/extractor/profile_properties.hpp
@@ -11,7 +11,7 @@ namespace extractor
struct ProfileProperties
{
ProfileProperties()
- : traffic_signal_penalty(0), u_turn_penalty(0), allow_u_turn_at_via(false), use_turn_restrictions(false)
+ : traffic_signal_penalty(0), u_turn_penalty(0), continue_straight_at_waypoint(true), use_turn_restrictions(false)
{
}
@@ -39,7 +39,7 @@ struct ProfileProperties
int traffic_signal_penalty;
//! penalty to do a uturn in deci-seconds
int u_turn_penalty;
- bool allow_u_turn_at_via;
+ bool continue_straight_at_waypoint;
bool use_turn_restrictions;
};
}
diff --git a/include/extractor/restriction_parser.hpp b/include/extractor/restriction_parser.hpp
index d2be8c1..8722bf1 100644
--- a/include/extractor/restriction_parser.hpp
+++ b/include/extractor/restriction_parser.hpp
@@ -19,7 +19,7 @@ namespace osrm
namespace extractor
{
-class ProfileProperties;
+struct ProfileProperties;
/**
* Parses the relations that represents turn restrictions.
diff --git a/include/server/api/base_parameters_grammar.hpp b/include/server/api/base_parameters_grammar.hpp
index 2f9a95e..4d441a5 100644
--- a/include/server/api/base_parameters_grammar.hpp
+++ b/include/server/api/base_parameters_grammar.hpp
@@ -3,22 +3,15 @@
#include "engine/api/base_parameters.hpp"
-#include "engine/polyline_compressor.hpp"
-#include "engine/hint.hpp"
#include "engine/bearing.hpp"
+#include "engine/hint.hpp"
+#include "engine/polyline_compressor.hpp"
-#include <boost/spirit/include/qi_lit.hpp>
-#include <boost/spirit/include/qi_char_.hpp>
-#include <boost/spirit/include/qi_int.hpp>
-#include <boost/spirit/include/qi_real.hpp>
-#include <boost/spirit/include/qi_grammar.hpp>
-#include <boost/spirit/include/qi_action.hpp>
-#include <boost/spirit/include/qi_optional.hpp>
-#include <boost/spirit/include/qi_attr_cast.hpp>
-#include <boost/spirit/include/qi_operator.hpp>
-#include <boost/spirit/include/qi_repeat.hpp>
-#include <boost/spirit/include/qi_as_string.hpp>
+#include <boost/optional.hpp>
+//#define BOOST_SPIRIT_DEBUG
+#include <boost/spirit/include/qi.hpp>
+#include <limits>
#include <string>
namespace osrm
@@ -29,60 +22,99 @@ namespace api
{
namespace qi = boost::spirit::qi;
+
+template <typename T, char... Fmt> struct no_trailing_dot_policy : qi::real_policies<T>
+{
+ template <typename Iterator> static bool parse_dot(Iterator &first, Iterator const &last)
+ {
+ if (first == last || *first != '.')
+ return false;
+
+ static const constexpr char fmt[sizeof...(Fmt)] = {Fmt...};
+
+ if (first + sizeof(fmt) < last && std::equal(fmt, fmt + sizeof(fmt), first + 1u))
+ return false;
+
+ ++first;
+ return true;
+ }
+
+ template <typename Iterator> static bool parse_exp(Iterator &, const Iterator &)
+ {
+ return false;
+ }
+
+ template <typename Iterator, typename Attribute>
+ static bool parse_exp_n(Iterator &, const Iterator &, Attribute &)
+ {
+ return false;
+ }
+
+ template <typename Iterator, typename Attribute>
+ static bool parse_nan(Iterator &, const Iterator &, Attribute &)
+ {
+ return false;
+ }
+
+ template <typename Iterator, typename Attribute>
+ static bool parse_inf(Iterator &, const Iterator &, Attribute &)
+ {
+ return false;
+ }
+};
+
struct BaseParametersGrammar : boost::spirit::qi::grammar<std::string::iterator>
{
using Iterator = std::string::iterator;
using RadiusesT = std::vector<boost::optional<double>>;
+ using json_policy = no_trailing_dot_policy<double, 'j', 's', 'o', 'n'>;
BaseParametersGrammar(qi::rule<Iterator> &root_rule_, engine::api::BaseParameters ¶meters_)
: BaseParametersGrammar::base_type(root_rule_), base_parameters(parameters_)
{
const auto add_bearing =
- [this](boost::optional<boost::fusion::vector2<short, short>> bearing_range)
- {
- boost::optional<engine::Bearing> bearing;
- if (bearing_range)
- {
- bearing = engine::Bearing{boost::fusion::at_c<0>(*bearing_range),
- boost::fusion::at_c<1>(*bearing_range)};
- }
- base_parameters.bearings.push_back(std::move(bearing));
- };
- const auto set_radiuses = [this](RadiusesT &radiuses)
- {
+ [this](boost::optional<boost::fusion::vector2<short, short>> bearing_range) {
+ boost::optional<engine::Bearing> bearing;
+ if (bearing_range)
+ {
+ bearing = engine::Bearing{boost::fusion::at_c<0>(*bearing_range),
+ boost::fusion::at_c<1>(*bearing_range)};
+ }
+ base_parameters.bearings.push_back(std::move(bearing));
+ };
+ const auto set_radiuses = [this](RadiusesT radiuses) {
base_parameters.radiuses = std::move(radiuses);
};
- const auto add_hint = [this](const std::string &hint_string)
- {
+ const auto add_hint = [this](const std::string &hint_string) {
if (hint_string.size() > 0)
{
base_parameters.hints.push_back(engine::Hint::FromBase64(hint_string));
}
};
- const auto add_coordinate = [this](const boost::fusion::vector<double, double> &lonLat)
- {
+ const auto add_coordinate = [this](const boost::fusion::vector<double, double> &lonLat) {
base_parameters.coordinates.emplace_back(util::Coordinate(
util::FixedLongitude(boost::fusion::at_c<0>(lonLat) * COORDINATE_PRECISION),
util::FixedLatitude(boost::fusion::at_c<1>(lonLat) * COORDINATE_PRECISION)));
};
- const auto polyline_to_coordinates = [this](const std::string &polyline)
- {
+ const auto polyline_to_coordinates = [this](const std::string &polyline) {
base_parameters.coordinates = engine::decodePolyline(polyline);
};
alpha_numeral = +qi::char_("a-zA-Z0-9");
polyline_chars = qi::char_("a-zA-Z0-9_.--[]{}@?|\\%~`^");
- base64_char = qi::char_("a-zA-Z0-9--_");
+ base64_char = qi::char_("a-zA-Z0-9--_=");
+
+ unlimited.add("unlimited", std::numeric_limits<double>::infinity());
- radiuses_rule = qi::lit("radiuses=") >> -qi::double_ % ";";
+ radiuses_rule = qi::lit("radiuses=") > -(unlimited | qi::double_) % ";";
hints_rule =
- qi::lit("hints=") >>
+ qi::lit("hints=") >
qi::as_string[qi::repeat(engine::ENCODED_HINT_SIZE)[base64_char]][add_hint] % ";";
bearings_rule =
- qi::lit("bearings=") >> (-(qi::short_ >> ',' >> qi::short_))[add_bearing] % ";";
- polyline_rule = qi::as_string[qi::lit("polyline(") >> +polyline_chars >>
- qi::lit(")")][polyline_to_coordinates];
- location_rule = (qi::double_ >> qi::lit(',') >> qi::double_)[add_coordinate];
+ qi::lit("bearings=") > (-(qi::short_ > ',' > qi::short_))[add_bearing] % ";";
+ polyline_rule = qi::as_string[qi::lit("polyline(") > +polyline_chars > qi::lit(")")]
+ [polyline_to_coordinates];
+ location_rule = (double_ > qi::lit(',') > double_)[add_coordinate];
query_rule = (location_rule % ';') | polyline_rule;
base_rule = bearings_rule | radiuses_rule[set_radiuses] | hints_rule;
@@ -97,9 +129,11 @@ struct BaseParametersGrammar : boost::spirit::qi::grammar<std::string::iterator>
qi::rule<Iterator> bearings_rule;
qi::rule<Iterator> hints_rule;
qi::rule<Iterator> polyline_rule, location_rule;
+ qi::symbols<char, double> unlimited;
qi::rule<Iterator, RadiusesT()> radiuses_rule;
qi::rule<Iterator, unsigned char()> base64_char;
qi::rule<Iterator, std::string()> alpha_numeral, polyline_chars;
+ qi::real_parser<double, json_policy> double_;
};
}
}
diff --git a/include/server/api/match_parameter_grammar.hpp b/include/server/api/match_parameter_grammar.hpp
index 7628e87..6671a58 100644
--- a/include/server/api/match_parameter_grammar.hpp
+++ b/include/server/api/match_parameter_grammar.hpp
@@ -2,15 +2,10 @@
#define MATCH_PARAMETERS_GRAMMAR_HPP
#include "engine/api/match_parameters.hpp"
-
#include "server/api/base_parameters_grammar.hpp"
-#include <boost/spirit/include/qi_lit.hpp>
-#include <boost/spirit/include/qi_uint.hpp>
-#include <boost/spirit/include/qi_bool.hpp>
-#include <boost/spirit/include/qi_grammar.hpp>
-#include <boost/spirit/include/qi_action.hpp>
-#include <boost/spirit/include/qi_optional.hpp>
+//#define BOOST_SPIRIT_DEBUG
+#include <boost/spirit/include/qi.hpp>
namespace osrm
{
@@ -31,47 +26,38 @@ struct MatchParametersGrammar final : public BaseParametersGrammar
MatchParametersGrammar() : BaseParametersGrammar(root_rule, parameters)
{
- const auto set_geojson_type = [this]()
- {
+ const auto set_geojson_type = [this] {
parameters.geometries = engine::api::RouteParameters::GeometriesType::GeoJSON;
};
- const auto set_polyline_type = [this]()
- {
+ const auto set_polyline_type = [this] {
parameters.geometries = engine::api::RouteParameters::GeometriesType::Polyline;
};
- const auto set_simplified_type = [this]()
- {
+ const auto set_simplified_type = [this] {
parameters.overview = engine::api::RouteParameters::OverviewType::Simplified;
};
- const auto set_full_type = [this]()
- {
+ const auto set_full_type = [this] {
parameters.overview = engine::api::RouteParameters::OverviewType::Full;
};
- const auto set_false_type = [this]()
- {
+ const auto set_false_type = [this] {
parameters.overview = engine::api::RouteParameters::OverviewType::False;
};
- const auto set_steps = [this](const StepsT steps)
- {
- parameters.steps = steps;
- };
- const auto set_timestamps = [this](TimestampsT ×tamps)
- {
+ const auto set_steps = [this](const StepsT steps) { parameters.steps = steps; };
+ const auto set_timestamps = [this](TimestampsT timestamps) {
parameters.timestamps = std::move(timestamps);
};
- steps_rule = qi::lit("steps=") >> qi::bool_;
+ steps_rule = qi::lit("steps=") > qi::bool_;
geometries_rule = qi::lit("geometries=geojson")[set_geojson_type] |
qi::lit("geometries=polyline")[set_polyline_type];
overview_rule = qi::lit("overview=simplified")[set_simplified_type] |
qi::lit("overview=full")[set_full_type] |
qi::lit("overview=false")[set_false_type];
- timestamps_rule = qi::lit("timestamps=") >> qi::uint_ % ";";
+ timestamps_rule = qi::lit("timestamps=") > qi::uint_ % ";";
match_rule = steps_rule[set_steps] | geometries_rule | overview_rule |
timestamps_rule[set_timestamps];
root_rule =
- query_rule >> -qi::lit(".json") >> -(qi::lit("?") >> (match_rule | base_rule) % '&');
+ query_rule > -qi::lit(".json") > -(qi::lit("?") > (match_rule | base_rule) % '&');
}
engine::api::MatchParameters parameters;
diff --git a/include/server/api/nearest_parameter_grammar.hpp b/include/server/api/nearest_parameter_grammar.hpp
index e51ccb5..09b6c2a 100644
--- a/include/server/api/nearest_parameter_grammar.hpp
+++ b/include/server/api/nearest_parameter_grammar.hpp
@@ -2,14 +2,10 @@
#define NEAREST_PARAMETERS_GRAMMAR_HPP
#include "engine/api/nearest_parameters.hpp"
-
#include "server/api/base_parameters_grammar.hpp"
-#include <boost/spirit/include/qi_lit.hpp>
-#include <boost/spirit/include/qi_uint.hpp>
-#include <boost/spirit/include/qi_grammar.hpp>
-#include <boost/spirit/include/qi_action.hpp>
-#include <boost/spirit/include/qi_optional.hpp>
+//#define BOOST_SPIRIT_DEBUG
+#include <boost/spirit/include/qi.hpp>
namespace osrm
{
@@ -26,13 +22,12 @@ struct NearestParametersGrammar final : public BaseParametersGrammar
NearestParametersGrammar() : BaseParametersGrammar(root_rule, parameters)
{
- const auto set_number = [this](const unsigned number)
- {
+ const auto set_number = [this](const unsigned number) {
parameters.number_of_results = number;
};
- nearest_rule = (qi::lit("number=") >> qi::uint_)[set_number];
+ nearest_rule = (qi::lit("number=") > qi::uint_)[set_number];
root_rule =
- query_rule >> -qi::lit(".json") >> -(qi::lit("?") >> (nearest_rule | base_rule) % '&');
+ query_rule > -qi::lit(".json") > -(qi::lit("?") > (nearest_rule | base_rule) % '&');
}
engine::api::NearestParameters parameters;
diff --git a/include/server/api/parameters_parser.hpp b/include/server/api/parameters_parser.hpp
index 5af5888..161910d 100644
--- a/include/server/api/parameters_parser.hpp
+++ b/include/server/api/parameters_parser.hpp
@@ -30,7 +30,7 @@ using is_parameter_t =
// Starts parsing and iter and modifies it until iter == end or parsing failed
template <typename ParameterT,
typename std::enable_if<detail::is_parameter_t<ParameterT>::value, int>::type = 0>
-boost::optional<ParameterT> parseParameters(std::string::iterator &iter, std::string::iterator end);
+boost::optional<ParameterT> parseParameters(std::string::iterator &iter, const std::string::iterator end);
// Copy on purpose because we need mutability
template <typename ParameterT,
diff --git a/include/server/api/parsed_url.hpp b/include/server/api/parsed_url.hpp
index 224f4a6..c805196 100644
--- a/include/server/api/parsed_url.hpp
+++ b/include/server/api/parsed_url.hpp
@@ -3,6 +3,8 @@
#include "util/coordinate.hpp"
+#include <boost/fusion/include/adapt_struct.hpp>
+
#include <string>
#include <vector>
@@ -13,15 +15,23 @@ namespace server
namespace api
{
-struct ParsedURL
+struct ParsedURL final
{
std::string service;
unsigned version;
std::string profile;
std::string query;
};
-}
-}
-}
+
+} // api
+} // server
+} // osrm
+
+BOOST_FUSION_ADAPT_STRUCT(osrm::server::api::ParsedURL,
+ (std::string, service)
+ (unsigned, version)
+ (std::string, profile)
+ (std::string, query)
+)
#endif
diff --git a/include/server/api/route_parameters_grammar.hpp b/include/server/api/route_parameters_grammar.hpp
index d85d435..d4280df 100644
--- a/include/server/api/route_parameters_grammar.hpp
+++ b/include/server/api/route_parameters_grammar.hpp
@@ -2,14 +2,10 @@
#define ROUTE_PARAMETERS_GRAMMAR_HPP
#include "engine/api/route_parameters.hpp"
-
#include "server/api/base_parameters_grammar.hpp"
-#include <boost/spirit/include/qi_lit.hpp>
-#include <boost/spirit/include/qi_bool.hpp>
-#include <boost/spirit/include/qi_grammar.hpp>
-#include <boost/spirit/include/qi_action.hpp>
-#include <boost/spirit/include/qi_optional.hpp>
+//#define BOOST_SPIRIT_DEBUG
+#include <boost/spirit/include/qi.hpp>
namespace osrm
{
@@ -31,53 +27,41 @@ struct RouteParametersGrammar : public BaseParametersGrammar
RouteParametersGrammar() : BaseParametersGrammar(root_rule, parameters)
{
- const auto set_geojson_type = [this]()
- {
+ const auto set_geojson_type = [this] {
parameters.geometries = engine::api::RouteParameters::GeometriesType::GeoJSON;
};
- const auto set_polyline_type = [this]()
- {
+ const auto set_polyline_type = [this] {
parameters.geometries = engine::api::RouteParameters::GeometriesType::Polyline;
};
- const auto set_simplified_type = [this]()
- {
+ const auto set_simplified_type = [this] {
parameters.overview = engine::api::RouteParameters::OverviewType::Simplified;
};
- const auto set_full_type = [this]()
- {
+ const auto set_full_type = [this] {
parameters.overview = engine::api::RouteParameters::OverviewType::Full;
};
- const auto set_false_type = [this]()
- {
+ const auto set_false_type = [this] {
parameters.overview = engine::api::RouteParameters::OverviewType::False;
};
- const auto set_steps = [this](const StepsT steps)
- {
- parameters.steps = steps;
- };
- const auto set_alternatives = [this](const AlternativeT alternatives)
- {
+ const auto set_steps = [this](const StepsT steps) { parameters.steps = steps; };
+ const auto set_alternatives = [this](const AlternativeT alternatives) {
parameters.alternatives = alternatives;
};
- const auto set_uturns = [this](UturnsT &uturns)
- {
- parameters.uturns = std::move(uturns);
- };
+ const auto set_continue_straight = [this](UturnsT continue_straight) { parameters.continue_straight = std::move(continue_straight); };
- alternatives_rule = qi::lit("alternatives=") >> qi::bool_;
- steps_rule = qi::lit("steps=") >> qi::bool_;
+ alternatives_rule = qi::lit("alternatives=") > qi::bool_;
+ steps_rule = qi::lit("steps=") > qi::bool_;
geometries_rule = qi::lit("geometries=geojson")[set_geojson_type] |
qi::lit("geometries=polyline")[set_polyline_type];
overview_rule = qi::lit("overview=simplified")[set_simplified_type] |
qi::lit("overview=full")[set_full_type] |
qi::lit("overview=false")[set_false_type];
- uturns_rule = qi::lit("uturns=default") | (qi::lit("uturns=") >> qi::bool_)[set_uturns];
+ continue_straight_rule = qi::lit("continue_straight=default") | (qi::lit("continue_straight=") > qi::bool_)[set_continue_straight];
route_rule = steps_rule[set_steps] | alternatives_rule[set_alternatives] | geometries_rule |
- overview_rule | uturns_rule;
+ overview_rule | continue_straight_rule;
root_rule =
- query_rule >> -qi::lit(".json") >> -(qi::lit("?") >> (route_rule | base_rule) % '&');
+ query_rule > -qi::lit(".json") > -(qi::lit("?") > (route_rule | base_rule) % '&');
}
engine::api::RouteParameters parameters;
@@ -85,7 +69,7 @@ struct RouteParametersGrammar : public BaseParametersGrammar
private:
qi::rule<Iterator> root_rule;
qi::rule<Iterator> route_rule, geometries_rule, overview_rule;
- qi::rule<Iterator, UturnsT()> uturns_rule;
+ qi::rule<Iterator, UturnsT()> continue_straight_rule;
qi::rule<Iterator, StepsT()> steps_rule;
qi::rule<Iterator, AlternativeT()> alternatives_rule;
};
diff --git a/include/server/api/table_parameter_grammar.hpp b/include/server/api/table_parameter_grammar.hpp
index d5acb04..00fe703 100644
--- a/include/server/api/table_parameter_grammar.hpp
+++ b/include/server/api/table_parameter_grammar.hpp
@@ -2,14 +2,10 @@
#define TABLE_PARAMETERS_GRAMMAR_HPP
#include "engine/api/table_parameters.hpp"
-
#include "server/api/base_parameters_grammar.hpp"
-#include <boost/spirit/include/qi_lit.hpp>
-#include <boost/spirit/include/qi_uint.hpp>
-#include <boost/spirit/include/qi_grammar.hpp>
-#include <boost/spirit/include/qi_action.hpp>
-#include <boost/spirit/include/qi_optional.hpp>
+//#define BOOST_SPIRIT_DEBUG
+#include <boost/spirit/include/qi.hpp>
namespace osrm
{
@@ -28,22 +24,28 @@ struct TableParametersGrammar final : public BaseParametersGrammar
TableParametersGrammar() : BaseParametersGrammar(root_rule, parameters)
{
- const auto set_destiantions = [this](DestinationsT &dests)
- {
+ const auto set_destiantions = [this](DestinationsT dests) {
parameters.destinations = std::move(dests);
};
- const auto set_sources = [this](SourcesT &sources)
- {
+ const auto set_sources = [this](SourcesT sources) {
parameters.sources = std::move(sources);
};
- destinations_rule = (qi::lit("destinations=") >> (qi::ulong_ % ";")[set_destiantions]) |
+// TODO: ulonglong -> size_t not only on Windows but on all 32 bit platforms; unsupported anyway as of now
+#ifdef WIN32
+ destinations_rule = (qi::lit("destinations=") > (qi::ulong_long % ";")[set_destiantions]) |
+ qi::lit("destinations=all");
+ sources_rule =
+ (qi::lit("sources=") > (qi::ulong_long % ";")[set_sources]) | qi::lit("sources=all");
+#else
+ destinations_rule = (qi::lit("destinations=") > (qi::ulong_ % ";")[set_destiantions]) |
qi::lit("destinations=all");
sources_rule =
- (qi::lit("sources=") >> (qi::ulong_ % ";")[set_sources]) | qi::lit("sources=all");
+ (qi::lit("sources=") > (qi::ulong_ % ";")[set_sources]) | qi::lit("sources=all");
+#endif
table_rule = destinations_rule | sources_rule;
root_rule =
- query_rule >> -qi::lit(".json") >> -(qi::lit("?") >> (table_rule | base_rule) % '&');
+ query_rule > -qi::lit(".json") > -(qi::lit("?") > (table_rule | base_rule) % '&');
}
engine::api::TableParameters parameters;
diff --git a/include/server/api/tile_parameter_grammar.hpp b/include/server/api/tile_parameter_grammar.hpp
index 2212b81..ef73357 100644
--- a/include/server/api/tile_parameter_grammar.hpp
+++ b/include/server/api/tile_parameter_grammar.hpp
@@ -3,14 +3,11 @@
#include "engine/api/tile_parameters.hpp"
-#include "engine/polyline_compressor.hpp"
#include "engine/hint.hpp"
+#include "engine/polyline_compressor.hpp"
-#include <boost/spirit/include/qi_lit.hpp>
-#include <boost/spirit/include/qi_uint.hpp>
-#include <boost/spirit/include/qi_grammar.hpp>
-#include <boost/spirit/include/qi_action.hpp>
-#include <boost/spirit/include/qi_operator.hpp>
+//#define BOOST_SPIRIT_DEBUG
+#include <boost/spirit/include/qi.hpp>
#include <string>
@@ -28,23 +25,15 @@ struct TileParametersGrammar final : boost::spirit::qi::grammar<std::string::ite
TileParametersGrammar() : TileParametersGrammar::base_type(root_rule)
{
- const auto set_x = [this](const unsigned x_)
- {
- parameters.x = x_;
- };
- const auto set_y = [this](const unsigned y_)
- {
- parameters.y = y_;
- };
- const auto set_z = [this](const unsigned z_)
- {
- parameters.z = z_;
- };
-
- query_rule = qi::lit("tile(") >> qi::uint_[set_x] >> qi::lit(",") >> qi::uint_[set_y] >>
- qi::lit(",") >> qi::uint_[set_z] >> qi::lit(")");
-
- root_rule = query_rule >> qi::lit(".mvt");
+ const auto set_x = [this](const unsigned x_) { parameters.x = x_; };
+ const auto set_y = [this](const unsigned y_) { parameters.y = y_; };
+ const auto set_z = [this](const unsigned z_) { parameters.z = z_; };
+
+ query_rule = qi::lit("tile(") > qi::uint_[set_x] //
+ > qi::lit(",") > qi::uint_[set_y] > //
+ qi::lit(",") > qi::uint_[set_z] > qi::lit(")"); //
+
+ root_rule = query_rule > qi::lit(".mvt");
}
engine::api::TileParameters parameters;
diff --git a/include/server/api/trip_parameter_grammar.hpp b/include/server/api/trip_parameter_grammar.hpp
index 3165d99..52c6622 100644
--- a/include/server/api/trip_parameter_grammar.hpp
+++ b/include/server/api/trip_parameter_grammar.hpp
@@ -2,15 +2,10 @@
#define TRIP_PARAMETERS_GRAMMAR_HPP
#include "engine/api/trip_parameters.hpp"
-
#include "server/api/base_parameters_grammar.hpp"
-#include <boost/spirit/include/qi_lit.hpp>
-#include <boost/spirit/include/qi_uint.hpp>
-#include <boost/spirit/include/qi_bool.hpp>
-#include <boost/spirit/include/qi_grammar.hpp>
-#include <boost/spirit/include/qi_action.hpp>
-#include <boost/spirit/include/qi_optional.hpp>
+//#define BOOST_SPIRIT_DEBUG
+#include <boost/spirit/include/qi.hpp>
namespace osrm
{
@@ -30,33 +25,25 @@ struct TripParametersGrammar final : public BaseParametersGrammar
TripParametersGrammar() : BaseParametersGrammar(root_rule, parameters)
{
- const auto set_geojson_type = [this]()
- {
+ const auto set_geojson_type = [this] {
parameters.geometries = engine::api::RouteParameters::GeometriesType::GeoJSON;
};
- const auto set_polyline_type = [this]()
- {
+ const auto set_polyline_type = [this] {
parameters.geometries = engine::api::RouteParameters::GeometriesType::Polyline;
};
- const auto set_simplified_type = [this]()
- {
+ const auto set_simplified_type = [this] {
parameters.overview = engine::api::RouteParameters::OverviewType::Simplified;
};
- const auto set_full_type = [this]()
- {
+ const auto set_full_type = [this] {
parameters.overview = engine::api::RouteParameters::OverviewType::Full;
};
- const auto set_false_type = [this]()
- {
+ const auto set_false_type = [this] {
parameters.overview = engine::api::RouteParameters::OverviewType::False;
};
- const auto set_steps = [this](const StepsT steps)
- {
- parameters.steps = steps;
- };
+ const auto set_steps = [this](const StepsT steps) { parameters.steps = steps; };
- steps_rule = qi::lit("steps=") >> qi::bool_;
+ steps_rule = qi::lit("steps=") > qi::bool_;
geometries_rule = qi::lit("geometries=geojson")[set_geojson_type] |
qi::lit("geometries=polyline")[set_polyline_type];
overview_rule = qi::lit("overview=simplified")[set_simplified_type] |
@@ -65,7 +52,7 @@ struct TripParametersGrammar final : public BaseParametersGrammar
trip_rule = steps_rule[set_steps] | geometries_rule | overview_rule;
root_rule =
- query_rule >> -qi::lit(".json") >> -(qi::lit("?") >> (trip_rule | base_rule) % '&');
+ query_rule > -qi::lit(".json") > -(qi::lit("?") > (trip_rule | base_rule) % '&');
}
engine::api::TripParameters parameters;
diff --git a/include/server/api/url_parser.hpp b/include/server/api/url_parser.hpp
index 0bac20f..5fcca36 100644
--- a/include/server/api/url_parser.hpp
+++ b/include/server/api/url_parser.hpp
@@ -15,8 +15,8 @@ namespace api
{
// Starts parsing and iter and modifies it until iter == end or parsing failed
-boost::optional<ParsedURL> parseURL(std::string::iterator &iter, std::string::iterator end);
-// copy on purpose because we need mutability
+boost::optional<ParsedURL> parseURL(std::string::iterator &iter, const std::string::iterator end);
+
inline boost::optional<ParsedURL> parseURL(std::string url_string)
{
auto iter = url_string.begin();
diff --git a/include/storage/storage.hpp b/include/storage/storage.hpp
index 31278aa..f5934dd 100644
--- a/include/storage/storage.hpp
+++ b/include/storage/storage.hpp
@@ -1,3 +1,30 @@
+/*
+
+Copyright (c) 2016, Project OSRM contributors
+All rights reserved.
+
+Redistribution and use in source and binary forms, with or without modification,
+are permitted provided that the following conditions are met:
+
+Redistributions of source code must retain the above copyright notice, this list
+of conditions and the following disclaimer.
+Redistributions in binary form must reproduce the above copyright notice, this
+list of conditions and the following disclaimer in the documentation and/or
+other materials provided with the distribution.
+
+THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
+ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
+WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
+DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR
+ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
+(INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
+LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON
+ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
+SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+
+*/
+
#ifndef STORAGE_HPP
#define STORAGE_HPP
diff --git a/include/storage/storage_config.hpp b/include/storage/storage_config.hpp
index e5e0e88..62f2fdd 100644
--- a/include/storage/storage_config.hpp
+++ b/include/storage/storage_config.hpp
@@ -1,3 +1,30 @@
+/*
+
+Copyright (c) 2016, Project OSRM contributors
+All rights reserved.
+
+Redistribution and use in source and binary forms, with or without modification,
+are permitted provided that the following conditions are met:
+
+Redistributions of source code must retain the above copyright notice, this list
+of conditions and the following disclaimer.
+Redistributions in binary form must reproduce the above copyright notice, this
+list of conditions and the following disclaimer in the documentation and/or
+other materials provided with the distribution.
+
+THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
+ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
+WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
+DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR
+ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
+(INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
+LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON
+ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
+SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+
+*/
+
#ifndef STORAGE_CONFIG_HPP
#define STORAGE_CONFIG_HPP
diff --git a/include/util/coordinate_calculation.hpp b/include/util/coordinate_calculation.hpp
index 806b538..afa6c65 100644
--- a/include/util/coordinate_calculation.hpp
+++ b/include/util/coordinate_calculation.hpp
@@ -3,7 +3,7 @@
#include "util/coordinate.hpp"
-#include <boost/math/constants/constants.hpp>
+#include <boost/optional.hpp>
#include <utility>
@@ -14,26 +14,18 @@ namespace util
namespace coordinate_calculation
{
+namespace detail
+{
const constexpr long double DEGREE_TO_RAD = 0.017453292519943295769236907684886;
const constexpr long double RAD_TO_DEGREE = 1. / DEGREE_TO_RAD;
// earth radius varies between 6,356.750-6,378.135 km (3,949.901-3,963.189mi)
// The IUGG value for the equatorial radius is 6378.137 km (3963.19 miles)
const constexpr long double EARTH_RADIUS = 6372797.560856;
-// radius used by WGS84
-const constexpr double EARTH_RADIUS_WGS84 = 6378137.0;
-
-namespace detail
-{
-// earth circumference devided by 2
-const constexpr double MAXEXTENT = EARTH_RADIUS_WGS84 * boost::math::constants::pi<double>();
-// ^ math functions are not constexpr since they have side-effects (setting errno) :(
-const double MAX_LATITUDE = RAD_TO_DEGREE * (2.0 * std::atan(std::exp(180.0 * DEGREE_TO_RAD)) -
- boost::math::constants::half_pi<double>());
-const constexpr double MAX_LONGITUDE = 180.0;
}
+
//! Takes the squared euclidean distance of the input coordinates. Does not return meters!
-double squaredEuclideanDistance(const FloatCoordinate &lhs, const FloatCoordinate &rhs);
+std::uint64_t squaredEuclideanDistance(const Coordinate &lhs, const Coordinate &rhs);
double haversineDistance(const Coordinate first_coordinate, const Coordinate second_coordinate);
@@ -61,30 +53,20 @@ double bearing(const Coordinate first_coordinate, const Coordinate second_coordi
// Get angle of line segment (A,C)->(C,B)
double computeAngle(const Coordinate first, const Coordinate second, const Coordinate third);
+// find the center of a circle through three coordinates
+boost::optional<Coordinate> circleCenter(const Coordinate first_coordinate,
+ const Coordinate second_coordinate,
+ const Coordinate third_coordinate);
+
+// find the radius of a circle through three coordinates
+double circleRadius(const Coordinate first_coordinate,
+ const Coordinate second_coordinate,
+ const Coordinate third_coordinate);
+
// factor in [0,1]. Returns point along the straight line between from and to. 0 returns from, 1
// returns to
Coordinate interpolateLinear(double factor, const Coordinate from, const Coordinate to);
-namespace mercator
-{
-// This is the global default tile size for all Mapbox Vector Tiles
-const constexpr double TILE_SIZE = 256.0;
-// Converts projected mercator degrees to PX
-const constexpr double DEGREE_TO_PX = detail::MAXEXTENT / 180.0;
-
-double degreeToPixel(FloatLatitude lat, unsigned zoom);
-double degreeToPixel(FloatLongitude lon, unsigned zoom);
-FloatLatitude yToLat(const double value);
-double latToY(const FloatLatitude latitude);
-
-FloatCoordinate fromWGS84(const FloatCoordinate &wgs84_coordinate);
-FloatCoordinate toWGS84(const FloatCoordinate &mercator_coordinate);
-
-void xyzToMercator(
- const int x, const int y, const int z, double &minx, double &miny, double &maxx, double &maxy);
-void xyzToWGS84(
- const int x, const int y, const int z, double &minx, double &miny, double &maxx, double &maxy);
-} // ns mercator
} // ns coordinate_calculation
} // ns util
} // ns osrm
diff --git a/include/util/name_table.hpp b/include/util/name_table.hpp
index 2f1887a..318cffc 100644
--- a/include/util/name_table.hpp
+++ b/include/util/name_table.hpp
@@ -1,8 +1,8 @@
#ifndef OSRM_UTIL_NAME_TABLE_HPP
#define OSRM_UTIL_NAME_TABLE_HPP
-#include "util/shared_memory_vector_wrapper.hpp"
#include "util/range_table.hpp"
+#include "util/shared_memory_vector_wrapper.hpp"
#include <string>
diff --git a/include/util/range_table.hpp b/include/util/range_table.hpp
index f012349..c1a12c2 100644
--- a/include/util/range_table.hpp
+++ b/include/util/range_table.hpp
@@ -4,8 +4,8 @@
#include "util/integer_range.hpp"
#include "util/shared_memory_vector_wrapper.hpp"
-#include <fstream>
#include <array>
+#include <fstream>
#include <utility>
namespace osrm
@@ -61,8 +61,7 @@ template <unsigned BLOCK_SIZE, bool USE_SHARED_MEMORY> class RangeTable
// construct table from length vector
template <typename VectorT> explicit RangeTable(const VectorT &lengths)
{
- const unsigned number_of_blocks = [&lengths]()
- {
+ const unsigned number_of_blocks = [&lengths]() {
unsigned num = (lengths.size() + 1) / (BLOCK_SIZE + 1);
if ((lengths.size() + 1) % (BLOCK_SIZE + 1) != 0)
{
@@ -169,7 +168,7 @@ template <unsigned BLOCK_SIZE, bool USE_SHARED_MEMORY> class RangeTable
end_idx = block_offsets[block_idx + 1];
}
- BOOST_ASSERT(begin_idx < sum_lengths && end_idx <= sum_lengths);
+ BOOST_ASSERT(end_idx <= sum_lengths);
BOOST_ASSERT(begin_idx <= end_idx);
return irange(begin_idx, end_idx);
diff --git a/include/util/rectangle.hpp b/include/util/rectangle.hpp
index fd0f871..ca7d84b 100644
--- a/include/util/rectangle.hpp
+++ b/include/util/rectangle.hpp
@@ -83,7 +83,7 @@ struct RectangleInt2D
// This code assumes that we are operating in euclidean space!
// That means if you just put unprojected lat/lon in here you will
// get invalid results.
- double GetMinSquaredDist(const Coordinate location) const
+ std::uint64_t GetMinSquaredDist(const Coordinate location) const
{
const bool is_contained = Contains(location);
if (is_contained)
@@ -116,7 +116,7 @@ struct RectangleInt2D
BOOST_ASSERT(d != INVALID);
- double min_dist = std::numeric_limits<double>::max();
+ std::uint64_t min_dist = std::numeric_limits<std::uint64_t>::max();
switch (d)
{
case NORTH:
@@ -155,7 +155,7 @@ struct RectangleInt2D
break;
}
- BOOST_ASSERT(min_dist < std::numeric_limits<double>::max());
+ BOOST_ASSERT(min_dist < std::numeric_limits<std::uint64_t>::max());
return min_dist;
}
diff --git a/include/util/static_rtree.hpp b/include/util/static_rtree.hpp
index 6924d94..32bd60b 100644
--- a/include/util/static_rtree.hpp
+++ b/include/util/static_rtree.hpp
@@ -5,11 +5,12 @@
#include "util/hilbert_value.hpp"
#include "util/rectangle.hpp"
#include "util/shared_memory_vector_wrapper.hpp"
-
#include "util/bearing.hpp"
-#include "util/integer_range.hpp"
#include "util/exception.hpp"
+#include "util/integer_range.hpp"
#include "util/typedefs.hpp"
+#include "util/coordinate_calculation.hpp"
+#include "util/web_mercator.hpp"
#include "osrm/coordinate.hpp"
@@ -42,7 +43,7 @@ template <class EdgeDataT,
class CoordinateListT = std::vector<Coordinate>,
bool UseSharedMemory = false,
std::uint32_t BRANCHING_FACTOR = 64,
- std::uint32_t LEAF_NODE_SIZE = 1024>
+ std::uint32_t LEAF_NODE_SIZE = 256>
class StaticRTree
{
public:
@@ -101,7 +102,7 @@ class StaticRTree
return other.squared_min_dist < squared_min_dist;
}
- double squared_min_dist;
+ std::uint64_t squared_min_dist;
QueryNodeType node;
};
@@ -145,9 +146,9 @@ class StaticRTree
Coordinate current_centroid = coordinate_calculation::centroid(
coordinate_list[current_element.u], coordinate_list[current_element.v]);
- current_centroid.lat = FixedLatitude(
- COORDINATE_PRECISION *
- coordinate_calculation::mercator::latToY(toFloating(current_centroid.lat)));
+ current_centroid.lat =
+ FixedLatitude(COORDINATE_PRECISION *
+ web_mercator::latToY(toFloating(current_centroid.lat)));
current_wrapper.m_hilbert_value = hilbertCode(current_centroid);
}
@@ -327,10 +328,10 @@ class StaticRTree
{
const Rectangle projected_rectangle{
search_rectangle.min_lon, search_rectangle.max_lon,
- toFixed(FloatLatitude{coordinate_calculation::mercator::latToY(
- toFloating(FixedLatitude(search_rectangle.min_lat)))}),
- toFixed(FloatLatitude{coordinate_calculation::mercator::latToY(
- toFloating(FixedLatitude(search_rectangle.max_lat)))})};
+ toFixed(FloatLatitude{
+ web_mercator::latToY(toFloating(FixedLatitude(search_rectangle.min_lat)))}),
+ toFixed(FloatLatitude{
+ web_mercator::latToY(toFloating(FixedLatitude(search_rectangle.max_lat)))})};
std::vector<EdgeDataT> results;
std::queue<TreeNode> traversal_queue;
@@ -409,12 +410,12 @@ class StaticRTree
Nearest(const Coordinate input_coordinate, const FilterT filter, const TerminationT terminate)
{
std::vector<EdgeDataT> results;
- auto projected_coordinate = coordinate_calculation::mercator::fromWGS84(input_coordinate);
+ auto projected_coordinate = web_mercator::fromWGS84(input_coordinate);
Coordinate fixed_projected_coordinate{projected_coordinate};
// initialize queue with root element
std::priority_queue<QueryCandidate> traversal_queue;
- traversal_queue.push(QueryCandidate{0.f, m_search_tree[0]});
+ traversal_queue.push(QueryCandidate{0, m_search_tree[0]});
while (!traversal_queue.empty())
{
@@ -427,8 +428,8 @@ class StaticRTree
current_query_node.node.template get<TreeNode>();
if (current_tree_node.child_is_on_disk)
{
- ExploreLeafNode(current_tree_node.children[0], projected_coordinate,
- traversal_queue);
+ ExploreLeafNode(current_tree_node.children[0], fixed_projected_coordinate,
+ projected_coordinate, traversal_queue);
}
else
{
@@ -439,11 +440,6 @@ class StaticRTree
{
// inspecting an actual road segment
auto ¤t_candidate = current_query_node.node.template get<CandidateSegment>();
- if (terminate(results.size(), current_candidate))
- {
- traversal_queue = std::priority_queue<QueryCandidate>{};
- break;
- }
auto use_segment = filter(current_candidate);
if (!use_segment.first && !use_segment.second)
@@ -455,6 +451,12 @@ class StaticRTree
// store phantom node in result vector
results.push_back(std::move(current_candidate.data));
+
+ if (terminate(results.size(), current_candidate))
+ {
+ traversal_queue = std::priority_queue<QueryCandidate>{};
+ break;
+ }
}
}
@@ -464,6 +466,7 @@ class StaticRTree
private:
template <typename QueueT>
void ExploreLeafNode(const std::uint32_t leaf_id,
+ const Coordinate projected_input_coordinate_fixed,
const FloatCoordinate &projected_input_coordinate,
QueueT &traversal_queue)
{
@@ -473,22 +476,19 @@ class StaticRTree
// current object represents a block on disk
for (const auto i : irange(0u, current_leaf_node.object_count))
{
- auto ¤t_edge = current_leaf_node.objects[i];
- auto projected_u =
- coordinate_calculation::mercator::fromWGS84((*m_coordinate_list)[current_edge.u]);
- auto projected_v =
- coordinate_calculation::mercator::fromWGS84((*m_coordinate_list)[current_edge.v]);
+ const auto ¤t_edge = current_leaf_node.objects[i];
+ const auto projected_u = web_mercator::fromWGS84((*m_coordinate_list)[current_edge.u]);
+ const auto projected_v = web_mercator::fromWGS84((*m_coordinate_list)[current_edge.v]);
FloatCoordinate projected_nearest;
std::tie(std::ignore, projected_nearest) =
coordinate_calculation::projectPointOnSegment(projected_u, projected_v,
projected_input_coordinate);
- auto squared_distance = coordinate_calculation::squaredEuclideanDistance(
- projected_input_coordinate, projected_nearest);
+ const auto squared_distance = coordinate_calculation::squaredEuclideanDistance(
+ projected_input_coordinate_fixed, projected_nearest);
// distance must be non-negative
BOOST_ASSERT(0. <= squared_distance);
-
traversal_queue.push(
QueryCandidate{squared_distance, CandidateSegment{Coordinate{projected_nearest},
std::move(current_edge)}});
@@ -540,10 +540,10 @@ class StaticRTree
BOOST_ASSERT(objects[i].u < coordinate_list.size());
BOOST_ASSERT(objects[i].v < coordinate_list.size());
- Coordinate projected_u{coordinate_calculation::mercator::fromWGS84(
- Coordinate{coordinate_list[objects[i].u]})};
- Coordinate projected_v{coordinate_calculation::mercator::fromWGS84(
- Coordinate{coordinate_list[objects[i].v]})};
+ Coordinate projected_u{
+ web_mercator::fromWGS84(Coordinate{coordinate_list[objects[i].u]})};
+ Coordinate projected_v{
+ web_mercator::fromWGS84(Coordinate{coordinate_list[objects[i].v]})};
BOOST_ASSERT(toFloating(projected_u.lon) <= FloatLongitude(180.));
BOOST_ASSERT(toFloating(projected_u.lon) >= FloatLongitude(-180.));
diff --git a/include/util/viewport.hpp b/include/util/viewport.hpp
index fd0ac73..211aa57 100644
--- a/include/util/viewport.hpp
+++ b/include/util/viewport.hpp
@@ -2,7 +2,7 @@
#define UTIL_VIEWPORT_HPP
#include "util/coordinate.hpp"
-#include "util/coordinate_calculation.hpp"
+#include "util/web_mercator.hpp"
#include <boost/assert.hpp>
@@ -23,27 +23,27 @@ namespace detail
static constexpr unsigned MAX_ZOOM = 18;
static constexpr unsigned MIN_ZOOM = 1;
// this is an upper bound to current display sizes
-static constexpr double VIEWPORT_WIDTH = 8 * coordinate_calculation::mercator::TILE_SIZE;
-static constexpr double VIEWPORT_HEIGHT = 5 * coordinate_calculation::mercator::TILE_SIZE;
+static constexpr double VIEWPORT_WIDTH = 8 * web_mercator::TILE_SIZE;
+static constexpr double VIEWPORT_HEIGHT = 5 * web_mercator::TILE_SIZE;
static double INV_LOG_2 = 1. / std::log(2);
}
-unsigned getFittedZoom(util::Coordinate south_west, util::Coordinate north_east)
+inline unsigned getFittedZoom(util::Coordinate south_west, util::Coordinate north_east)
{
- const auto min_x = coordinate_calculation::mercator::degreeToPixel(toFloating(south_west.lon), detail::MAX_ZOOM);
- const auto max_y = coordinate_calculation::mercator::degreeToPixel(toFloating(south_west.lat), detail::MAX_ZOOM);
- const auto max_x = coordinate_calculation::mercator::degreeToPixel(toFloating(north_east.lon), detail::MAX_ZOOM);
- const auto min_y = coordinate_calculation::mercator::degreeToPixel(toFloating(north_east.lat), detail::MAX_ZOOM);
+ const auto min_x = web_mercator::degreeToPixel(toFloating(south_west.lon), detail::MAX_ZOOM);
+ const auto max_y = web_mercator::degreeToPixel(toFloating(south_west.lat), detail::MAX_ZOOM);
+ const auto max_x = web_mercator::degreeToPixel(toFloating(north_east.lon), detail::MAX_ZOOM);
+ const auto min_y = web_mercator::degreeToPixel(toFloating(north_east.lat), detail::MAX_ZOOM);
const double width_ratio = (max_x - min_x) / detail::VIEWPORT_WIDTH;
const double height_ratio = (max_y - min_y) / detail::VIEWPORT_HEIGHT;
- const auto zoom = detail::MAX_ZOOM - std::max(std::log(width_ratio), std::log(height_ratio)) * detail::INV_LOG_2;
+ const auto zoom = detail::MAX_ZOOM -
+ std::max(std::log(width_ratio), std::log(height_ratio)) * detail::INV_LOG_2;
if (std::isfinite(zoom))
return std::max<unsigned>(detail::MIN_ZOOM, zoom);
else
- return detail::MIN_ZOOM;
+ return detail::MIN_ZOOM;
}
-
}
}
}
diff --git a/include/util/web_mercator.hpp b/include/util/web_mercator.hpp
new file mode 100644
index 0000000..8c23de1
--- /dev/null
+++ b/include/util/web_mercator.hpp
@@ -0,0 +1,127 @@
+#ifndef OSRM_WEB_MERCATOR_HPP
+#define OSRM_WEB_MERCATOR_HPP
+
+#include "util/coordinate.hpp"
+
+#include <boost/math/constants/constants.hpp>
+
+namespace osrm
+{
+namespace util
+{
+namespace web_mercator
+{
+namespace detail
+{
+const constexpr long double DEGREE_TO_RAD = 0.017453292519943295769236907684886;
+const constexpr long double RAD_TO_DEGREE = 1. / DEGREE_TO_RAD;
+// radius used by WGS84
+const constexpr double EARTH_RADIUS_WGS84 = 6378137.0;
+// earth circumference devided by 2
+const constexpr double MAXEXTENT = EARTH_RADIUS_WGS84 * boost::math::constants::pi<double>();
+// ^ math functions are not constexpr since they have side-effects (setting errno) :(
+const constexpr double MAX_LATITUDE = 85.;
+const constexpr double MAX_LONGITUDE = 180.0;
+}
+
+// Converts projected mercator degrees to PX
+const constexpr double DEGREE_TO_PX = detail::MAXEXTENT / 180.0;
+// This is the global default tile size for all Mapbox Vector Tiles
+const constexpr double TILE_SIZE = 256.0;
+
+inline FloatLatitude yToLat(const double y)
+{
+ const auto clamped_y = std::max(-180., std::min(180., y));
+ const double normalized_lat =
+ detail::RAD_TO_DEGREE * 2. * std::atan(std::exp(clamped_y * detail::DEGREE_TO_RAD));
+
+ return FloatLatitude(normalized_lat - 90.);
+}
+
+inline double latToY(const FloatLatitude latitude)
+{
+ // apparently this is the (faster) version of the canonical log(tan()) version
+ const double f = std::sin(detail::DEGREE_TO_RAD * static_cast<double>(latitude));
+ const double y = detail::RAD_TO_DEGREE * 0.5 * std::log((1 + f) / (1 - f));
+ const auto clamped_y = std::max(-180., std::min(180., y));
+ return clamped_y;
+}
+
+inline FloatLatitude clamp(const FloatLatitude lat)
+{
+ return std::max(std::min(lat, FloatLatitude(detail::MAX_LATITUDE)),
+ FloatLatitude(-detail::MAX_LATITUDE));
+}
+
+inline FloatLongitude clamp(const FloatLongitude lon)
+{
+ return std::max(std::min(lon, FloatLongitude(detail::MAX_LONGITUDE)),
+ FloatLongitude(-detail::MAX_LONGITUDE));
+}
+
+inline void pixelToDegree(const double shift, double &x, double &y)
+{
+ const double b = shift / 2.0;
+ x = (x - b) / shift * 360.0;
+ // FIXME needs to be simplified
+ const double g = (y - b) / -(shift / (2 * M_PI)) / detail::DEGREE_TO_RAD;
+ static_assert(detail::DEGREE_TO_RAD / (2 * M_PI) - 1 / 360. < 0.0001, "");
+ y = static_cast<double>(yToLat(g));
+}
+
+inline double degreeToPixel(FloatLongitude lon, unsigned zoom)
+{
+ const double shift = (1u << zoom) * TILE_SIZE;
+ const double b = shift / 2.0;
+ const double x = b * (1 + static_cast<double>(lon) / 180.0);
+ return x;
+}
+
+inline double degreeToPixel(FloatLatitude lat, unsigned zoom)
+{
+ const double shift = (1u << zoom) * TILE_SIZE;
+ const double b = shift / 2.0;
+ const double y = b * (1. - latToY(lat) / 180.);
+ return y;
+}
+
+inline FloatCoordinate fromWGS84(const FloatCoordinate &wgs84_coordinate)
+{
+ return {wgs84_coordinate.lon, FloatLatitude{latToY(wgs84_coordinate.lat)}};
+}
+
+inline FloatCoordinate toWGS84(const FloatCoordinate &mercator_coordinate)
+{
+ return {mercator_coordinate.lon, yToLat(static_cast<double>(mercator_coordinate.lat))};
+}
+
+// Converts a WMS tile coordinate (z,x,y) into a wgs bounding box
+inline void xyzToWGS84(
+ const int x, const int y, const int z, double &minx, double &miny, double &maxx, double &maxy)
+{
+ minx = x * TILE_SIZE;
+ miny = (y + 1.0) * TILE_SIZE;
+ maxx = (x + 1.0) * TILE_SIZE;
+ maxy = y * TILE_SIZE;
+ // 2^z * TILE_SIZE
+ const double shift = (1u << static_cast<unsigned>(z)) * TILE_SIZE;
+ pixelToDegree(shift, minx, miny);
+ pixelToDegree(shift, maxx, maxy);
+}
+
+// Converts a WMS tile coordinate (z,x,y) into a mercator bounding box
+inline void xyzToMercator(
+ const int x, const int y, const int z, double &minx, double &miny, double &maxx, double &maxy)
+{
+ xyzToWGS84(x, y, z, minx, miny, maxx, maxy);
+
+ minx = static_cast<double>(clamp(util::FloatLongitude(minx))) * DEGREE_TO_PX;
+ miny = latToY(clamp(util::FloatLatitude(miny))) * DEGREE_TO_PX;
+ maxx = static_cast<double>(clamp(util::FloatLongitude(maxx))) * DEGREE_TO_PX;
+ maxy = latToY(clamp(util::FloatLatitude(maxy))) * DEGREE_TO_PX;
+}
+}
+}
+}
+
+#endif
diff --git a/profiles/bicycle.lua b/profiles/bicycle.lua
index 5575747..84e02d8 100644
--- a/profiles/bicycle.lua
+++ b/profiles/bicycle.lua
@@ -6,9 +6,9 @@ local limit = require("lib/maxspeed").limit
-- Begin of globals
barrier_whitelist = { [""] = true, ["cycle_barrier"] = true, ["bollard"] = true, ["entrance"] = true, ["cattle_grid"] = true, ["border_control"] = true, ["toll_booth"] = true, ["sally_port"] = true, ["gate"] = true, ["no"] = true, ["block"] = true }
access_tag_whitelist = { ["yes"] = true, ["permissive"] = true, ["designated"] = true }
-access_tag_blacklist = { ["no"] = true, ["private"] = true, ["agricultural"] = true, ["forestry"] = true }
+access_tag_blacklist = { ["no"] = true, ["private"] = true, ["agricultural"] = true, ["forestry"] = true, ["delivery"] = true }
access_tag_restricted = { ["destination"] = true, ["delivery"] = true }
-access_tags_hierachy = { "bicycle", "vehicle", "access" }
+access_tags_hierarchy = { "bicycle", "vehicle", "access" }
cycleway_tags = {["track"]=true,["lane"]=true,["opposite"]=true,["opposite_lane"]=true,["opposite_track"]=true,["share_busway"]=true,["sharrow"]=true,["shared"]=true }
service_tag_restricted = { ["parking_aisle"] = true }
restriction_exception_tags = { "bicycle", "vehicle", "access" }
@@ -91,10 +91,10 @@ surface_speeds = {
}
-- these need to be global because they are accesed externaly
-properties.traffic_signal_penalty = 2
-properties.use_turn_restrictions = false
-properties.u_turn_penalty = 20
-properties.allow_u_turn_at_via = true
+properties.traffic_signal_penalty = 2
+properties.use_turn_restrictions = false
+properties.u_turn_penalty = 20
+properties.continue_straight_at_waypoint = false
local obey_oneway = true
local ignore_areas = true
@@ -131,7 +131,7 @@ function node_function (node, result)
local highway = node:get_value_by_key("highway")
local is_crossing = highway and highway == "crossing"
- local access = find_access_tag(node, access_tags_hierachy)
+ local access = find_access_tag(node, access_tags_hierarchy)
if access and access ~= "" then
-- access restrictions on crossing nodes are not relevant for
-- the traffic on the road
@@ -180,7 +180,7 @@ function way_function (way, result)
end
-- access
- local access = find_access_tag(way, access_tags_hierachy)
+ local access = find_access_tag(way, access_tags_hierarchy)
if access and access_tag_blacklist[access] then
return
end
diff --git a/profiles/car.lua b/profiles/car.lua
index 8b1e7f2..4033f31 100644
--- a/profiles/car.lua
+++ b/profiles/car.lua
@@ -5,10 +5,9 @@ local find_access_tag = require("lib/access").find_access_tag
-- Begin of globals
barrier_whitelist = { ["cattle_grid"] = true, ["border_control"] = true, ["checkpoint"] = true, ["toll_booth"] = true, ["sally_port"] = true, ["gate"] = true, ["lift_gate"] = true, ["no"] = true, ["entrance"] = true }
access_tag_whitelist = { ["yes"] = true, ["motorcar"] = true, ["motor_vehicle"] = true, ["vehicle"] = true, ["permissive"] = true, ["designated"] = true, ["destination"] = true }
-access_tag_blacklist = { ["no"] = true, ["private"] = true, ["agricultural"] = true, ["forestry"] = true, ["emergency"] = true, ["psv"] = true }
+access_tag_blacklist = { ["no"] = true, ["private"] = true, ["agricultural"] = true, ["forestry"] = true, ["emergency"] = true, ["psv"] = true, ["delivery"] = true }
access_tag_restricted = { ["destination"] = true, ["delivery"] = true }
-access_tags = { "motorcar", "motor_vehicle", "vehicle" }
-access_tags_hierachy = { "motorcar", "motor_vehicle", "vehicle", "access" }
+access_tags_hierarchy = { "motorcar", "motor_vehicle", "vehicle", "access" }
service_tag_restricted = { ["parking_aisle"] = true }
restriction_exception_tags = { "motorcar", "motor_vehicle", "vehicle" }
@@ -125,13 +124,15 @@ maxspeed_table = {
["gb:motorway"] = (70*1609)/1000,
["uk:nsl_single"] = (60*1609)/1000,
["uk:nsl_dual"] = (70*1609)/1000,
- ["uk:motorway"] = (70*1609)/1000
+ ["uk:motorway"] = (70*1609)/1000,
+ ["none"] = 140
}
-- set profile properties
properties.u_turn_penalty = 20
properties.traffic_signal_penalty = 2
properties.use_turn_restrictions = true
+properties.continue_straight_at_waypoint = true
local side_road_speed_multiplier = 0.8
@@ -181,7 +182,7 @@ end
function node_function (node, result)
-- parse access and barrier tags
- local access = find_access_tag(node, access_tags_hierachy)
+ local access = find_access_tag(node, access_tags_hierarchy)
if access and access ~= "" then
if access_tag_blacklist[access] then
result.barrier = true
@@ -238,7 +239,7 @@ function way_function (way, result)
end
-- Check if we are allowed to access the way
- local access = find_access_tag(way, access_tags_hierachy)
+ local access = find_access_tag(way, access_tags_hierarchy)
if access_tag_blacklist[access] then
return
end
diff --git a/profiles/foot.lua b/profiles/foot.lua
index af1f76e..04f16c2 100644
--- a/profiles/foot.lua
+++ b/profiles/foot.lua
@@ -5,9 +5,9 @@ local find_access_tag = require("lib/access").find_access_tag
-- Begin of globals
barrier_whitelist = { [""] = true, ["cycle_barrier"] = true, ["bollard"] = true, ["entrance"] = true, ["cattle_grid"] = true, ["border_control"] = true, ["toll_booth"] = true, ["sally_port"] = true, ["gate"] = true, ["no"] = true, ["block"] = true}
access_tag_whitelist = { ["yes"] = true, ["foot"] = true, ["permissive"] = true, ["designated"] = true }
-access_tag_blacklist = { ["no"] = true, ["private"] = true, ["agricultural"] = true, ["forestry"] = true }
+access_tag_blacklist = { ["no"] = true, ["private"] = true, ["agricultural"] = true, ["forestry"] = true, ["delivery"] = true }
access_tag_restricted = { ["destination"] = true, ["delivery"] = true }
-access_tags_hierachy = { "foot", "access" }
+access_tags_hierarchy = { "foot", "access" }
service_tag_restricted = { ["parking_aisle"] = true }
ignore_in_grid = { ["ferry"] = true }
restriction_exception_tags = { "foot" }
@@ -64,10 +64,10 @@ leisure_speeds = {
["track"] = walking_speed
}
-properties.traffic_signal_penalty = 2
-properties.u_turn_penalty = 2
-properties.use_turn_restrictions = false
-properties.allow_u_turn_at_via = true
+properties.traffic_signal_penalty = 2
+properties.u_turn_penalty = 2
+properties.use_turn_restrictions = false
+properties.continue_straight_at_waypoint = false
local fallback_names = true
@@ -79,7 +79,7 @@ end
function node_function (node, result)
local barrier = node:get_value_by_key("barrier")
- local access = find_access_tag(node, access_tags_hierachy)
+ local access = find_access_tag(node, access_tags_hierarchy)
local traffic_signal = node:get_value_by_key("highway")
-- flag node if it carries a traffic light
@@ -131,7 +131,7 @@ function way_function (way, result)
end
-- access
- local access = find_access_tag(way, access_tags_hierachy)
+ local access = find_access_tag(way, access_tags_hierarchy)
if access_tag_blacklist[access] then
return
end
diff --git a/profiles/lib/access.lua b/profiles/lib/access.lua
index 3fd4ff6..3433c65 100644
--- a/profiles/lib/access.lua
+++ b/profiles/lib/access.lua
@@ -2,8 +2,8 @@ local ipairs = ipairs
local Access = {}
-function Access.find_access_tag(source,access_tags_hierachy)
- for i,v in ipairs(access_tags_hierachy) do
+function Access.find_access_tag(source,access_tags_hierarchy)
+ for i,v in ipairs(access_tags_hierarchy) do
local tag = source:get_value_by_key(v)
if tag and tag ~= '' then
return tag
diff --git a/profiles/testbot.lua b/profiles/testbot.lua
index aecffae..8bad810 100644
--- a/profiles/testbot.lua
+++ b/profiles/testbot.lua
@@ -16,10 +16,10 @@ speed_profile = {
-- these settings are read directly by osrm
-properties.allow_u_turn_at_via = false
-properties.use_turn_restrictions = true
-properties.traffic_signal_penalty = 7 -- seconds
-properties.u_turn_penalty = 20
+properties.continue_straight_at_waypoint = true
+properties.use_turn_restrictions = true
+properties.traffic_signal_penalty = 7 -- seconds
+properties.u_turn_penalty = 20
function limit_speed(speed, limits)
-- don't use ipairs(), since it stops at the first nil value
diff --git a/scripts/poly2req.js b/scripts/poly2req.js
new file mode 100755
index 0000000..5b446f3
--- /dev/null
+++ b/scripts/poly2req.js
@@ -0,0 +1,132 @@
+#!/usr/bin/env node
+
+'use strict';
+
+let fs = require('fs');
+
+let VERSION = "route_5.0";
+let SAMPLE_SIZE = 20;
+let NUM_REQUEST = 1000;
+let NUM_COORDS = 2;
+let PORT = 5000;
+let url_templates = {
+ "route_5.0": "http://127.0.0.1:{port}/route/v1/driving/{coords}?steps=false&alternatives=false",
+ "route_4.9": "http://127.0.0.1:{port}/viaroute?{coords}&instructions=false&alt=false",
+ "table_5.0": "http://127.0.0.1:{port}/table/v1/driving/{coords}",
+ "table_4.9": "http://127.0.0.1:{port}/table?{coords}"
+};
+
+let coord_templates = {
+ "route_5.0": "{lon},{lat}",
+ "route_4.9": "loc={lat},{lon}",
+ "table_5.0": "{lon},{lat}",
+ "table_4.9": "loc={lat},{lon}"
+};
+
+let coords_separators = {
+ "route_5.0": ";",
+ "route_4.9": "&",
+ "table_5.0": ";",
+ "table_4.9": "&"
+};
+var axis = "distance";
+
+var sw = [Number.MAX_VALUE, Number.MAX_VALUE];
+var ne = [Number.MIN_VALUE, Number.MIN_VALUE];
+
+if (process.argv.length > 2 && process.argv[2] == "planet")
+{
+ sw = [-180., -85.];
+ ne = [180., 85.];
+}
+if (process.argv.length > 2 && process.argv[2] == "us")
+{
+ sw = [-127., 24.];
+ ne = [-67., 48.];
+}
+else if (process.argv.length > 2 && process.argv[2] == "dc")
+{
+ sw = [-77.138, 38.808];
+ ne = [-76.909, 38.974];
+}
+else if (process.argv.length > 2)
+{
+ let monaco_poly_path = process.argv[2];
+ let poly_data = fs.readFileSync(monaco_poly_path, 'utf-8');
+
+ // lets assume there is only one ring
+ // cut of name and ring number and the two END statements
+ let coordinates = poly_data.split('\n')
+ .filter((l) => l != '')
+ .slice(2, -2).map((coord_line) => coord_line.split(' ')
+ .filter((elem) => elem != ''))
+ .map((coord) => [parseFloat(coord[0]), parseFloat(coord[1])]);
+
+ coordinates.forEach((c) => {
+ sw[0] = Math.min(sw[0], c[0]);
+ sw[1] = Math.min(sw[1], c[1]);
+ ne[0] = Math.max(ne[0], c[0]);
+ ne[1] = Math.max(ne[1], c[1]);
+ });
+}
+
+if (process.argv.length > 3)
+{
+ axis = process.argv[3];
+}
+
+console.error(sw);
+console.error(ne);
+
+// Yes this an own seeded random number generator because its only a few lines
+var seed = 0x1337;
+function seededRandom(min, max) {
+ seed = (seed * 9301 + 49297) % 233280;
+ var rnd = seed / 233280;
+ return min + rnd * (max - min);
+}
+
+function getRandomCoordinate() {
+ let lon = seededRandom(sw[0], ne[0]);
+ let lat = seededRandom(sw[1], ne[1]);
+ return [lon, lat];
+}
+
+function makeQuery(coords) {
+ let coords_string = coords.map((c) => coord_templates[VERSION].replace("{lon}", c[0]).replace("{lat}", c[1])).join(coords_separators[VERSION]);
+ return url_templates[VERSION].replace("{coords}", coords_string).replace("{port}", PORT);
+}
+
+if (axis == "distance")
+{
+ for (var i = 0; i < NUM_REQUEST; ++i)
+ {
+ var coords = [];
+ for (var j = 0; j < NUM_COORDS; ++j)
+ {
+ coords.push(getRandomCoordinate());
+ }
+ console.log(makeQuery(coords));
+ }
+}
+else if (axis == "waypoints")
+{
+ for (var power = 0; power <= 1; ++power)
+ {
+ for (var factor = 1; factor <= 10; ++factor)
+ {
+ let num_coords = factor*Math.pow(10, power);
+ console.error(num_coords);
+ for (var i = 0; i < SAMPLE_SIZE; ++i)
+ {
+ var coords = [];
+ for (var j = 0; j < num_coords; ++j)
+ {
+ coords.push(getRandomCoordinate());
+ }
+ console.log(makeQuery(coords));
+ }
+ }
+ }
+}
+
diff --git a/scripts/timer.sh b/scripts/timer.sh
new file mode 100755
index 0000000..39d8e5b
--- /dev/null
+++ b/scripts/timer.sh
@@ -0,0 +1,12 @@
+#!/bin/bash
+
+TIMINGS_FILE=/tmp/osrm.timings
+NAME=$1
+CMD=${@:2}
+START=$(date "+%s.%N")
+/bin/bash -c "$CMD"
+END=$(date "+%s.%N")
+TIME="$(echo "$END - $START" | bc)s"
+NEW_ENTRY="$NAME\t$TIME\t$(date -Iseconds)"
+
+echo -e "$NEW_ENTRY" >> $TIMINGS_FILE
diff --git a/src/benchmarks/CMakeLists.txt b/src/benchmarks/CMakeLists.txt
new file mode 100644
index 0000000..754dc75
--- /dev/null
+++ b/src/benchmarks/CMakeLists.txt
@@ -0,0 +1,20 @@
+file(GLOB RTreeBenchmarkSources
+ *.cpp)
+
+add_executable(rtree-bench
+ EXCLUDE_FROM_ALL
+ ${RTreeBenchmarkSources}
+ $<TARGET_OBJECTS:UTIL>)
+
+target_include_directories(rtree-bench
+ PUBLIC
+ ${PROJECT_SOURCE_DIR}/unit_tests)
+
+target_link_libraries(rtree-bench
+ ${Boost_LIBRARIES}
+ ${CMAKE_THREAD_LIBS_INIT}
+ ${TBB_LIBRARIES})
+
+add_custom_target(benchmarks
+ DEPENDS
+ rtree-bench)
diff --git a/src/contractor/contractor.cpp b/src/contractor/contractor.cpp
index 39d6f48..72b2d34 100644
--- a/src/contractor/contractor.cpp
+++ b/src/contractor/contractor.cpp
@@ -626,7 +626,7 @@ Contractor::WriteContractedGraph(unsigned max_node_id,
int number_of_used_edges = 0;
util::StaticGraph<EdgeData>::EdgeArrayEntry current_edge;
- for (const auto edge : util::irange<std::size_t>(0, contracted_edge_list.size()))
+ for (const auto edge : util::irange<std::size_t>(0UL, contracted_edge_list.size()))
{
// some self-loops are required for oneway handling. Need to assertthat we only keep these
// (TODO)
diff --git a/src/engine/api/json_factory.cpp b/src/engine/api/json_factory.cpp
index 5c3663d..b1f5da5 100644
--- a/src/engine/api/json_factory.cpp
+++ b/src/engine/api/json_factory.cpp
@@ -1,16 +1,16 @@
#include "engine/api/json_factory.hpp"
-#include "engine/polyline_compressor.hpp"
#include "engine/hint.hpp"
+#include "engine/polyline_compressor.hpp"
+#include "util/integer_range.hpp"
#include <boost/assert.hpp>
-#include <boost/range/irange.hpp>
#include <boost/optional.hpp>
-#include <string>
-#include <utility>
#include <algorithm>
#include <iterator>
+#include <string>
+#include <utility>
#include <vector>
using TurnType = osrm::extractor::guidance::TurnType;
@@ -28,23 +28,17 @@ namespace json
namespace detail
{
-const constexpr char *modifier_names[] = {"uturn",
- "sharp right",
- "right",
- "slight right",
- "straight",
- "slight left",
- "left",
- "sharp left"};
+const constexpr char *modifier_names[] = {"uturn", "sharp right", "right", "slight right",
+ "straight", "slight left", "left", "sharp left"};
// translations of TurnTypes. Not all types are exposed to the outside world.
// invalid types should never be returned as part of the API
const constexpr char *turn_type_names[] = {
- "invalid", "no turn", "invalid", "new name", "continue", "turn",
- "turn", "turn", "turn", "turn", "merge", "ramp",
- "ramp", "ramp", "ramp", "ramp", "fork", "end of road",
- "roundabout", "invalid", "roundabout", "invalid", "traffic circle", "invalid",
- "traffic circle", "invalid", "invalid", "restriction", "notification"};
+ "invalid", "no turn", "invalid", "new name", "continue", "turn",
+ "turn", "turn", "turn", "turn", "merge", "ramp",
+ "ramp", "ramp", "ramp", "ramp", "fork", "end of road",
+ "roundabout", "invalid", "roundabout", "invalid", "rotary", "invalid",
+ "rotary", "invalid", "invalid", "restriction", "notification"};
const constexpr char *waypoint_type_names[] = {"invalid", "arrive", "depart"};
// Check whether to include a modifier in the result of the API
@@ -144,6 +138,7 @@ util::json::Object makeStepManeuver(const guidance::StepManeuver &maneuver)
if (detail::isValidModifier(maneuver))
step_maneuver.values["modifier"] =
detail::instructionModifierToString(maneuver.instruction.direction_modifier);
+
step_maneuver.values["location"] = detail::coordinateToLonLat(maneuver.location);
step_maneuver.values["bearing_before"] = std::round(maneuver.bearing_before);
step_maneuver.values["bearing_after"] = std::round(maneuver.bearing_after);
@@ -164,6 +159,9 @@ util::json::Object makeRouteStep(guidance::RouteStep step, util::json::Value geo
route_step.values["distance"] = std::round(step.distance * 10) / 10.;
route_step.values["duration"] = std::round(step.duration * 10) / 10.;
route_step.values["name"] = std::move(step.name);
+ if (!step.rotary_name.empty())
+ route_step.values["rotary_name"] = std::move(step.rotary_name);
+
route_step.values["mode"] = detail::modeToString(std::move(step.mode));
route_step.values["maneuver"] = makeStepManeuver(std::move(step.maneuver));
route_step.values["geometry"] = std::move(geometry);
@@ -199,7 +197,6 @@ util::json::Object makeRouteLeg(guidance::RouteLeg leg, util::json::Array steps)
util::json::Object route_leg;
route_leg.values["distance"] = std::round(leg.distance * 10) / 10.;
route_leg.values["duration"] = std::round(leg.duration * 10) / 10.;
- route_leg.values["summary"] = std::move(leg.summary);
route_leg.values["steps"] = std::move(steps);
return route_leg;
}
@@ -209,15 +206,14 @@ util::json::Array makeRouteLegs(std::vector<guidance::RouteLeg> legs,
{
util::json::Array json_legs;
auto step_geometry_iter = step_geometries.begin();
- for (const auto idx : boost::irange(0UL, legs.size()))
+ for (const auto idx : util::irange<std::size_t>(0UL, legs.size()))
{
auto leg = std::move(legs[idx]);
util::json::Array json_steps;
json_steps.values.reserve(leg.steps.size());
std::transform(
std::make_move_iterator(leg.steps.begin()), std::make_move_iterator(leg.steps.end()),
- std::back_inserter(json_steps.values), [&step_geometry_iter](guidance::RouteStep step)
- {
+ std::back_inserter(json_steps.values), [&step_geometry_iter](guidance::RouteStep step) {
return makeRouteStep(std::move(step), std::move(*step_geometry_iter++));
});
json_legs.values.push_back(makeRouteLeg(std::move(leg), std::move(json_steps)));
diff --git a/src/engine/douglas_peucker.cpp b/src/engine/douglas_peucker.cpp
index e7e2f90..a3eb762 100644
--- a/src/engine/douglas_peucker.cpp
+++ b/src/engine/douglas_peucker.cpp
@@ -1,9 +1,10 @@
#include "engine/douglas_peucker.hpp"
-#include "util/coordinate_calculation.hpp"
#include "util/coordinate.hpp"
+#include "util/coordinate_calculation.hpp"
+#include "util/integer_range.hpp"
+#include "util/web_mercator.hpp"
#include <boost/assert.hpp>
-#include <boost/range/irange.hpp>
#include <cmath>
#include <algorithm>
@@ -16,6 +17,31 @@ namespace osrm
namespace engine
{
+struct FastPerpendicularDistance
+{
+ FastPerpendicularDistance(const util::Coordinate start, const util::Coordinate target)
+ : projected_start(util::web_mercator::fromWGS84(start)),
+ projected_target(util::web_mercator::fromWGS84(target))
+ {
+ }
+
+ // Normed to the thresholds table
+ std::uint64_t operator()(const util::Coordinate coordinate) const
+ {
+ auto projected = util::web_mercator::fromWGS84(coordinate);
+ util::FloatCoordinate projected_point_on_segment;
+ std::tie(std::ignore, projected_point_on_segment) =
+ util::coordinate_calculation::projectPointOnSegment(projected_start, projected_target,
+ projected);
+ auto squared_distance = util::coordinate_calculation::squaredEuclideanDistance(projected,
+ projected_point_on_segment);
+ return squared_distance;
+ }
+
+ const util::FloatCoordinate projected_start;
+ const util::FloatCoordinate projected_target;
+};
+
std::vector<util::Coordinate> douglasPeucker(std::vector<util::Coordinate>::const_iterator begin,
std::vector<util::Coordinate>::const_iterator end,
const unsigned zoom_level)
@@ -23,7 +49,7 @@ std::vector<util::Coordinate> douglasPeucker(std::vector<util::Coordinate>::cons
BOOST_ASSERT_MSG(zoom_level < detail::DOUGLAS_PEUCKER_THRESHOLDS_SIZE,
"unsupported zoom level");
- const auto size = std::distance(begin, end);
+ const std::size_t size = std::distance(begin, end);
if (size < 2)
{
return {};
@@ -51,14 +77,16 @@ std::vector<util::Coordinate> douglasPeucker(std::vector<util::Coordinate>::cons
BOOST_ASSERT_MSG(pair.second < size, "right border outside of geometry");
BOOST_ASSERT_MSG(pair.first <= pair.second, "left border on the wrong side");
- double max_distance = 0;
+ std::uint64_t max_distance = 0;
auto farthest_entry_index = pair.second;
+ FastPerpendicularDistance perpendicular_distance(begin[pair.first], begin[pair.second]);
+
// sweep over range to find the maximum
for (auto idx = pair.first + 1; idx != pair.second; ++idx)
{
using namespace util::coordinate_calculation;
- const auto distance = perpendicularDistance(begin[pair.first], begin[pair.second], begin[idx]);
+ const auto distance = perpendicular_distance(begin[idx]);
// found new feasible maximum?
if (distance > max_distance &&
distance > detail::DOUGLAS_PEUCKER_THRESHOLDS[zoom_level])
@@ -87,7 +115,7 @@ std::vector<util::Coordinate> douglasPeucker(std::vector<util::Coordinate>::cons
auto simplified_size = std::count(is_necessary.begin(), is_necessary.end(), true);
std::vector<util::Coordinate> simplified_geometry;
simplified_geometry.reserve(simplified_size);
- for (auto idx : boost::irange<std::size_t>(0UL, size))
+ for (auto idx : util::irange<std::size_t>(0UL, size))
{
if (is_necessary[idx])
{
diff --git a/src/engine/guidance/post_processing.cpp b/src/engine/guidance/post_processing.cpp
index 0f3fc34..6d02a07 100644
--- a/src/engine/guidance/post_processing.cpp
+++ b/src/engine/guidance/post_processing.cpp
@@ -1,16 +1,16 @@
#include "engine/guidance/post_processing.hpp"
#include "extractor/guidance/turn_instruction.hpp"
-#include "engine/guidance/toolkit.hpp"
#include "engine/guidance/assemble_steps.hpp"
+#include "engine/guidance/toolkit.hpp"
#include <boost/assert.hpp>
#include <boost/range/algorithm_ext/erase.hpp>
#include <algorithm>
-#include <iostream>
#include <cmath>
#include <cstddef>
+#include <iostream>
#include <limits>
#include <utility>
@@ -54,6 +54,11 @@ void fixFinalRoundabout(std::vector<RouteStep> &steps)
{
propagation_step.maneuver.exit = 0;
propagation_step.geometry_end = steps.back().geometry_begin;
+
+ if (propagation_step.maneuver.instruction.type == TurnType::EnterRotary ||
+ propagation_step.maneuver.instruction.type == TurnType::EnterRotaryAtExit)
+ propagation_step.rotary_name = propagation_step.name;
+
break;
}
else if (propagation_step.maneuver.instruction.type == TurnType::StayOnRoundabout)
@@ -80,18 +85,20 @@ bool setUpRoundabout(RouteStep &step)
step.maneuver.exit = 1;
// prevent futher special case handling of these two.
if (instruction.type == TurnType::EnterRotaryAtExit)
- step.maneuver.instruction = TurnType::EnterRotary;
+ step.maneuver.instruction.type = TurnType::EnterRotary;
else
- step.maneuver.instruction = TurnType::EnterRoundabout;
+ step.maneuver.instruction.type = TurnType::EnterRoundabout;
}
if (leavesRoundabout(instruction))
{
step.maneuver.exit = 1; // count the otherwise missing exit
- if (instruction.type == TurnType::EnterRotaryAtExit)
- step.maneuver.instruction = TurnType::EnterRotary;
+
+ // prevent futher special case handling of these two.
+ if (instruction.type == TurnType::EnterAndExitRotary)
+ step.maneuver.instruction.type = TurnType::EnterRotary;
else
- step.maneuver.instruction = TurnType::EnterRoundabout;
+ step.maneuver.instruction.type = TurnType::EnterRoundabout;
return false;
}
else
@@ -123,6 +130,8 @@ void closeOffRoundabout(const bool on_roundabout,
steps[1].maneuver.instruction.type = step.maneuver.instruction.type == TurnType::ExitRotary
? TurnType::EnterRotary
: TurnType::EnterRoundabout;
+ if (steps[1].maneuver.instruction.type == TurnType::EnterRotary)
+ steps[1].rotary_name = steps[0].name;
}
// Normal exit from the roundabout, or exit from a previously fixed roundabout.
@@ -144,6 +153,11 @@ void closeOffRoundabout(const bool on_roundabout,
propagation_step.maneuver.exit = step.maneuver.exit;
propagation_step.geometry_end = step.geometry_end;
+ // remember rotary name
+ if (propagation_step.maneuver.instruction.type == TurnType::EnterRotary ||
+ propagation_step.maneuver.instruction.type == TurnType::EnterRotaryAtExit)
+ propagation_step.rotary_name = propagation_step.name;
+
propagation_step.name = step.name;
propagation_step.name_id = step.name_id;
break;
@@ -205,9 +219,8 @@ std::vector<RouteStep> postProcess(std::vector<RouteStep> steps)
// adds an intersection to the initial route step
// It includes the length of the last step, until the intersection
// Also updates the length of the respective segment
- auto addIntersection =
- [](RouteStep into, const RouteStep &last_step, const RouteStep &intersection)
- {
+ auto addIntersection = [](RouteStep into, const RouteStep &last_step,
+ const RouteStep &intersection) {
into.maneuver.intersections.push_back(
{last_step.duration, last_step.distance, intersection.maneuver.location});
@@ -280,8 +293,7 @@ std::vector<RouteStep> postProcess(std::vector<RouteStep> steps)
// Two valid NO_TURNs exist in each leg in the form of Depart/Arrive
// keep valid instructions
- const auto not_is_valid = [](const RouteStep &step)
- {
+ const auto not_is_valid = [](const RouteStep &step) {
return step.maneuver.instruction == TurnInstruction::NO_TURN() &&
step.maneuver.waypoint_type == WaypointType::None;
};
@@ -338,10 +350,8 @@ void trimShortSegments(std::vector<RouteStep> &steps, LegGeometry &geometry)
// geometry offsets have to be adjusted. Move all offsets to the front and reduce by
// one. (This is an inplace forward one and reduce by one)
std::transform(geometry.segment_offsets.begin() + 1, geometry.segment_offsets.end(),
- geometry.segment_offsets.begin(), [](const std::size_t val)
- {
- return val - 1;
- });
+ geometry.segment_offsets.begin(),
+ [](const std::size_t val) { return val - 1; });
geometry.segment_offsets.pop_back();
const auto ¤t_depart = steps.front();
@@ -364,21 +374,18 @@ void trimShortSegments(std::vector<RouteStep> &steps, LegGeometry &geometry)
steps.front().geometry_begin = 1;
// reduce all offsets by one (inplace)
std::transform(geometry.segment_offsets.begin(), geometry.segment_offsets.end(),
- geometry.segment_offsets.begin(), [](const std::size_t val)
- {
- return val - 1;
- });
+ geometry.segment_offsets.begin(),
+ [](const std::size_t val) { return val - 1; });
steps.front().maneuver = detail::stepManeuverFromGeometry(
TurnInstruction::NO_TURN(), WaypointType::Depart, geometry);
}
// and update the leg geometry indices for the removed entry
- std::for_each(steps.begin(), steps.end(), [](RouteStep &step)
- {
- --step.geometry_begin;
- --step.geometry_end;
- });
+ std::for_each(steps.begin(), steps.end(), [](RouteStep &step) {
+ --step.geometry_begin;
+ --step.geometry_end;
+ });
}
// make sure we still have enough segments
@@ -419,7 +426,9 @@ void trimShortSegments(std::vector<RouteStep> &steps, LegGeometry &geometry)
// This can happen if the last coordinate snaps to a node in the unpacked geometry
geometry.locations.pop_back();
geometry.segment_offsets.back()--;
- BOOST_ASSERT(next_to_last_step.geometry_end == steps.back().geometry_begin);
+ // since the last geometry includes the location of arrival, the arrival instruction
+ // geometry overlaps with the previous segment
+ BOOST_ASSERT(next_to_last_step.geometry_end == steps.back().geometry_begin + 1);
BOOST_ASSERT(next_to_last_step.geometry_begin < next_to_last_step.geometry_end);
next_to_last_step.geometry_end--;
steps.back().geometry_begin--;
@@ -482,7 +491,7 @@ LegGeometry resyncGeometry(LegGeometry leg_geometry, const std::vector<RouteStep
leg_geometry.segment_offsets.push_back(step.geometry_end - 1);
}
- // remove the data fromt the reached-target step again
+ // remove the data from the reached-target step again
leg_geometry.segment_offsets.pop_back();
leg_geometry.segment_distances.pop_back();
diff --git a/src/engine/plugins/match.cpp b/src/engine/plugins/match.cpp
index 1fff3fe..bd3a970 100644
--- a/src/engine/plugins/match.cpp
+++ b/src/engine/plugins/match.cpp
@@ -168,7 +168,7 @@ Status MatchPlugin::HandleRequest(const api::MatchParameters ¶meters,
}
std::vector<InternalRouteResult> sub_routes(sub_matchings.size());
- for (auto index : util::irange(0UL, sub_matchings.size()))
+ for (auto index : util::irange<std::size_t>(0UL, sub_matchings.size()))
{
BOOST_ASSERT(sub_matchings[index].nodes.size() > 1);
@@ -183,7 +183,9 @@ Status MatchPlugin::HandleRequest(const api::MatchParameters ¶meters,
BOOST_ASSERT(current_phantom_node_pair.target_phantom.IsValid());
sub_routes[index].segment_end_coordinates.emplace_back(current_phantom_node_pair);
}
- shortest_path(sub_routes[index].segment_end_coordinates, {}, sub_routes[index]);
+ // force uturns to be on, since we split the phantom nodes anyway and only have bi-directional
+ // phantom nodes for possible uturns
+ shortest_path(sub_routes[index].segment_end_coordinates, {true}, sub_routes[index]);
BOOST_ASSERT(sub_routes[index].shortest_path_length != INVALID_EDGE_WEIGHT);
}
diff --git a/src/engine/plugins/tile.cpp b/src/engine/plugins/tile.cpp
index 7d18d90..87586ea 100644
--- a/src/engine/plugins/tile.cpp
+++ b/src/engine/plugins/tile.cpp
@@ -2,6 +2,7 @@
#include "engine/plugins/tile.hpp"
#include "util/coordinate_calculation.hpp"
+#include "util/web_mercator.hpp"
#include <boost/geometry.hpp>
#include <boost/geometry/geometries/point_xy.hpp>
@@ -119,7 +120,6 @@ FixedLine coordinatesToTileLine(const util::Coordinate start,
const util::Coordinate target,
const detail::BBox &tile_bbox)
{
- using namespace util::coordinate_calculation;
FloatLine geo_line;
geo_line.emplace_back(static_cast<double>(util::toFloating(start.lon)),
static_cast<double>(util::toFloating(start.lat)));
@@ -130,15 +130,16 @@ FixedLine coordinatesToTileLine(const util::Coordinate start,
for (auto const &pt : geo_line)
{
- double px_merc = pt.x * mercator::DEGREE_TO_PX;
- double py_merc = mercator::latToY(util::FloatLatitude(pt.y)) * mercator::DEGREE_TO_PX;
+ double px_merc = pt.x * util::web_mercator::DEGREE_TO_PX;
+ double py_merc = util::web_mercator::latToY(util::FloatLatitude(pt.y)) *
+ util::web_mercator::DEGREE_TO_PX;
// convert lon/lat to tile coordinates
const auto px = std::round(
- ((px_merc - tile_bbox.minx) * mercator::TILE_SIZE / tile_bbox.width()) *
- detail::VECTOR_TILE_EXTENT / util::coordinate_calculation::mercator::TILE_SIZE);
+ ((px_merc - tile_bbox.minx) * util::web_mercator::TILE_SIZE / tile_bbox.width()) *
+ detail::VECTOR_TILE_EXTENT / util::web_mercator::TILE_SIZE);
const auto py = std::round(
- ((tile_bbox.maxy - py_merc) * mercator::TILE_SIZE / tile_bbox.height()) *
- detail::VECTOR_TILE_EXTENT / util::coordinate_calculation::mercator::TILE_SIZE);
+ ((tile_bbox.maxy - py_merc) * util::web_mercator::TILE_SIZE / tile_bbox.height()) *
+ detail::VECTOR_TILE_EXTENT / util::web_mercator::TILE_SIZE);
boost::geometry::append(unclipped_line, point_t(px, py));
}
@@ -170,12 +171,11 @@ Status TilePlugin::HandleRequest(const api::TileParameters ¶meters, std::str
{
BOOST_ASSERT(parameters.IsValid());
- using namespace util::coordinate_calculation;
double min_lon, min_lat, max_lon, max_lat;
// Convert the z,x,y mercator tile coordinates into WGS84 lon/lat values
- mercator::xyzToWGS84(parameters.x, parameters.y, parameters.z, min_lon, min_lat, max_lon,
- max_lat);
+ util::web_mercator::xyzToWGS84(parameters.x, parameters.y, parameters.z, min_lon, min_lat,
+ max_lon, max_lat);
util::Coordinate southwest{util::FloatLongitude(min_lon), util::FloatLatitude(min_lat)};
util::Coordinate northeast{util::FloatLongitude(max_lon), util::FloatLatitude(max_lat)};
@@ -245,8 +245,8 @@ Status TilePlugin::HandleRequest(const api::TileParameters ¶meters, std::str
// TODO: extract speed values for compressed and uncompressed geometries
// Convert tile coordinates into mercator coordinates
- mercator::xyzToMercator(parameters.x, parameters.y, parameters.z, min_lon, min_lat, max_lon,
- max_lat);
+ util::web_mercator::xyzToMercator(parameters.x, parameters.y, parameters.z, min_lon, min_lat,
+ max_lon, max_lat);
const detail::BBox tile_bbox{min_lon, min_lat, max_lon, max_lat};
// Protobuf serialized blocks when objects go out of scope, hence
diff --git a/src/engine/plugins/trip.cpp b/src/engine/plugins/trip.cpp
index c834f46..35c6514 100644
--- a/src/engine/plugins/trip.cpp
+++ b/src/engine/plugins/trip.cpp
@@ -135,7 +135,7 @@ InternalRouteResult TripPlugin::ComputeRoute(const std::vector<PhantomNode> &sna
}
BOOST_ASSERT(min_route.segment_end_coordinates.size() == trip.size());
- shortest_path(min_route.segment_end_coordinates, parameters.uturns, min_route);
+ shortest_path(min_route.segment_end_coordinates, parameters.continue_straight, min_route);
BOOST_ASSERT_MSG(min_route.shortest_path_length < INVALID_EDGE_WEIGHT, "unroutable route");
return min_route;
diff --git a/src/engine/plugins/viaroute.cpp b/src/engine/plugins/viaroute.cpp
index ffd62b3..748151a 100644
--- a/src/engine/plugins/viaroute.cpp
+++ b/src/engine/plugins/viaroute.cpp
@@ -58,24 +58,26 @@ Status ViaRoutePlugin::HandleRequest(const api::RouteParameters &route_parameter
auto snapped_phantoms = SnapPhantomNodes(phantom_node_pairs);
- const bool allow_u_turn_at_via =
- route_parameters.uturns ? *route_parameters.uturns : facade.GetUTurnsDefault();
+ const bool continue_straight_at_waypoint = route_parameters.continue_straight
+ ? *route_parameters.continue_straight
+ : facade.GetContinueStraightDefault();
InternalRouteResult raw_route;
- auto build_phantom_pairs = [&raw_route, allow_u_turn_at_via](const PhantomNode &first_node,
- const PhantomNode &second_node)
+ auto build_phantom_pairs = [&raw_route, continue_straight_at_waypoint](
+ const PhantomNode &first_node, const PhantomNode &second_node)
{
raw_route.segment_end_coordinates.push_back(PhantomNodes{first_node, second_node});
auto &last_inserted = raw_route.segment_end_coordinates.back();
// enable forward direction if possible
if (last_inserted.source_phantom.forward_segment_id.id != SPECIAL_SEGMENTID)
{
- last_inserted.source_phantom.forward_segment_id.enabled |= allow_u_turn_at_via;
+ last_inserted.source_phantom.forward_segment_id.enabled |=
+ !continue_straight_at_waypoint;
}
// enable reverse direction if possible
if (last_inserted.source_phantom.reverse_segment_id.id != SPECIAL_SEGMENTID)
{
- last_inserted.source_phantom.reverse_segment_id.enabled |= allow_u_turn_at_via;
+ last_inserted.source_phantom.reverse_segment_id.enabled |= !continue_straight_at_waypoint;
}
};
util::for_each_pair(snapped_phantoms, build_phantom_pairs);
@@ -93,7 +95,7 @@ Status ViaRoutePlugin::HandleRequest(const api::RouteParameters &route_parameter
}
else
{
- shortest_path(raw_route.segment_end_coordinates, route_parameters.uturns, raw_route);
+ shortest_path(raw_route.segment_end_coordinates, route_parameters.continue_straight, raw_route);
}
// we can only know this after the fact, different SCC ids still
diff --git a/src/extractor/edge_based_graph_factory.cpp b/src/extractor/edge_based_graph_factory.cpp
index 4cbde57..6264fcd 100644
--- a/src/extractor/edge_based_graph_factory.cpp
+++ b/src/extractor/edge_based_graph_factory.cpp
@@ -2,12 +2,12 @@
#include "extractor/edge_based_graph_factory.hpp"
#include "util/coordinate.hpp"
#include "util/coordinate_calculation.hpp"
-#include "util/percent.hpp"
+#include "util/exception.hpp"
#include "util/integer_range.hpp"
#include "util/lua_util.hpp"
+#include "util/percent.hpp"
#include "util/simple_logger.hpp"
#include "util/timing_util.hpp"
-#include "util/exception.hpp"
#include "extractor/guidance/toolkit.hpp"
@@ -122,8 +122,7 @@ void EdgeBasedGraphFactory::InsertEdgeBasedNode(const NodeID node_u, const NodeI
NodeID current_edge_source_coordinate_id = node_u;
- const auto edge_id_to_segment_id = [](const NodeID edge_based_node_id)
- {
+ const auto edge_id_to_segment_id = [](const NodeID edge_based_node_id) {
if (edge_based_node_id == SPECIAL_NODEID)
{
return SegmentID{SPECIAL_SEGMENTID, false};
@@ -133,7 +132,7 @@ void EdgeBasedGraphFactory::InsertEdgeBasedNode(const NodeID node_u, const NodeI
};
// traverse arrays from start and end respectively
- for (const auto i : util::irange(std::size_t{ 0 }, geometry_size))
+ for (const auto i : util::irange(std::size_t{0}, geometry_size))
{
BOOST_ASSERT(
current_edge_source_coordinate_id ==
@@ -325,7 +324,7 @@ void EdgeBasedGraphFactory::GenerateEdgeExpandedEdges(
m_barrier_nodes, m_compressed_edge_container, name_table);
for (const auto node_u : util::irange(0u, m_node_based_graph->GetNumberOfNodes()))
{
- // progress.printStatus(node_u);
+ progress.printStatus(node_u);
for (const EdgeID edge_from_u : m_node_based_graph->GetAdjacentEdgeRange(node_u))
{
if (m_node_based_graph->GetEdgeData(edge_from_u).reversed)
@@ -468,6 +467,8 @@ int EdgeBasedGraphFactory::GetTurnPenalty(double angle, lua_State *lua_state) co
{
// call lua profile to compute turn penalty
double penalty = luabind::call_function<double>(lua_state, "turn_function", 180. - angle);
+ BOOST_ASSERT(penalty < std::numeric_limits<int>::max());
+ BOOST_ASSERT(penalty > std::numeric_limits<int>::min());
return boost::numeric_cast<int>(penalty);
}
catch (const luabind::error &er)
diff --git a/src/extractor/extractor.cpp b/src/extractor/extractor.cpp
index 368867d..99f25ae 100644
--- a/src/extractor/extractor.cpp
+++ b/src/extractor/extractor.cpp
@@ -544,7 +544,7 @@ void Extractor::BuildRTree(std::vector<EdgeBasedNode> node_based_edge_list,
// Filter node based edges based on startpoint
auto out_iter = node_based_edge_list.begin();
auto in_iter = node_based_edge_list.begin();
- for (auto index : util::irange<std::size_t>(0, node_is_startpoint.size()))
+ for (auto index : util::irange<std::size_t>(0UL, node_is_startpoint.size()))
{
BOOST_ASSERT(in_iter != node_based_edge_list.end());
if (node_is_startpoint[index])
diff --git a/src/extractor/extractor_callbacks.cpp b/src/extractor/extractor_callbacks.cpp
index a289ec6..0e07d93 100644
--- a/src/extractor/extractor_callbacks.cpp
+++ b/src/extractor/extractor_callbacks.cpp
@@ -14,6 +14,7 @@
#include "osrm/coordinate.hpp"
+#include <iterator>
#include <limits>
#include <string>
#include <vector>
diff --git a/src/extractor/guidance/intersection.cpp b/src/extractor/guidance/intersection.cpp
new file mode 100644
index 0000000..8902ba4
--- /dev/null
+++ b/src/extractor/guidance/intersection.cpp
@@ -0,0 +1,31 @@
+#include "extractor/guidance/intersection.hpp"
+
+namespace osrm
+{
+namespace extractor
+{
+namespace guidance
+{
+
+ConnectedRoad::ConnectedRoad(const TurnOperation turn, const bool entry_allowed)
+ : entry_allowed(entry_allowed), turn(turn)
+{
+}
+
+std::string toString(const ConnectedRoad &road)
+{
+ std::string result = "[connection] ";
+ result += std::to_string(road.turn.eid);
+ result += " allows entry: ";
+ result += std::to_string(road.entry_allowed);
+ result += " angle: ";
+ result += std::to_string(road.turn.angle);
+ result += " instruction: ";
+ result += std::to_string(static_cast<std::int32_t>(road.turn.instruction.type)) + " " +
+ std::to_string(static_cast<std::int32_t>(road.turn.instruction.direction_modifier));
+ return result;
+}
+
+} // namespace guidance
+} // namespace extractor
+} // namespace osrm
diff --git a/src/extractor/guidance/intersection_generator.cpp b/src/extractor/guidance/intersection_generator.cpp
new file mode 100644
index 0000000..5f01cda
--- /dev/null
+++ b/src/extractor/guidance/intersection_generator.cpp
@@ -0,0 +1,255 @@
+#include "extractor/guidance/constants.hpp"
+#include "extractor/guidance/intersection_generator.hpp"
+#include "extractor/guidance/toolkit.hpp"
+
+#include <algorithm>
+#include <iterator>
+#include <limits>
+#include <utility>
+
+namespace osrm
+{
+namespace extractor
+{
+namespace guidance
+{
+
+IntersectionGenerator::IntersectionGenerator(const util::NodeBasedDynamicGraph &node_based_graph,
+ const RestrictionMap &restriction_map,
+ const std::unordered_set<NodeID> &barrier_nodes,
+ const std::vector<QueryNode> &node_info_list,
+ const CompressedEdgeContainer &compressed_edge_container)
+ : node_based_graph(node_based_graph), restriction_map(restriction_map),
+ barrier_nodes(barrier_nodes), node_info_list(node_info_list),
+ compressed_edge_container(compressed_edge_container)
+{
+}
+
+Intersection IntersectionGenerator::operator()(const NodeID from_node, const EdgeID via_eid) const
+{
+ return getConnectedRoads(from_node, via_eid);
+}
+
+// a
+// |
+// |
+// v
+// For an intersection from_node --via_edi--> turn_node ----> c
+// ^
+// |
+// |
+// b
+// This functions returns _all_ turns as if the graph was undirected.
+// That means we not only get (from_node, turn_node, c) in the above example
+// but also (from_node, turn_node, a), (from_node, turn_node, b). These turns are
+// marked as invalid and only needed for intersection classification.
+Intersection IntersectionGenerator::getConnectedRoads(const NodeID from_node,
+ const EdgeID via_eid) const
+{
+ Intersection intersection;
+ const NodeID turn_node = node_based_graph.GetTarget(via_eid);
+ const NodeID only_restriction_to_node =
+ restriction_map.CheckForEmanatingIsOnlyTurn(from_node, turn_node);
+ const bool is_barrier_node = barrier_nodes.find(turn_node) != barrier_nodes.end();
+
+ bool has_uturn_edge = false;
+ for (const EdgeID onto_edge : node_based_graph.GetAdjacentEdgeRange(turn_node))
+ {
+ BOOST_ASSERT(onto_edge != SPECIAL_EDGEID);
+ const NodeID to_node = node_based_graph.GetTarget(onto_edge);
+
+ bool turn_is_valid =
+ // reverse edges are never valid turns because the resulting turn would look like this:
+ // from_node --via_edge--> turn_node <--onto_edge-- to_node
+ // however we need this for capture intersection shape for incoming one-ways
+ !node_based_graph.GetEdgeData(onto_edge).reversed &&
+ // we are not turning over a barrier
+ (!is_barrier_node || from_node == to_node) &&
+ // We are at an only_-restriction but not at the right turn.
+ (only_restriction_to_node == SPECIAL_NODEID || to_node == only_restriction_to_node) &&
+ // the turn is not restricted
+ !restriction_map.CheckIfTurnIsRestricted(from_node, turn_node, to_node);
+
+ auto angle = 0.;
+ if (from_node == to_node)
+ {
+ if (turn_is_valid && !is_barrier_node)
+ {
+ // we only add u-turns for dead-end streets.
+ if (node_based_graph.GetOutDegree(turn_node) > 1)
+ {
+ auto number_of_emmiting_bidirectional_edges = 0;
+ for (auto edge : node_based_graph.GetAdjacentEdgeRange(turn_node))
+ {
+ auto target = node_based_graph.GetTarget(edge);
+ auto reverse_edge = node_based_graph.FindEdge(target, turn_node);
+ BOOST_ASSERT(reverse_edge != SPECIAL_EDGEID);
+ if (!node_based_graph.GetEdgeData(reverse_edge).reversed)
+ {
+ ++number_of_emmiting_bidirectional_edges;
+ }
+ }
+ // is a dead-end
+ turn_is_valid = number_of_emmiting_bidirectional_edges <= 1;
+ }
+ }
+ has_uturn_edge = true;
+ BOOST_ASSERT(angle >= 0. && angle < std::numeric_limits<double>::epsilon());
+ }
+ else
+ {
+ // unpack first node of second segment if packed
+ const auto first_coordinate = getRepresentativeCoordinate(
+ from_node, turn_node, via_eid, INVERT, compressed_edge_container, node_info_list);
+ const auto third_coordinate = getRepresentativeCoordinate(
+ turn_node, to_node, onto_edge, !INVERT, compressed_edge_container, node_info_list);
+ angle = util::coordinate_calculation::computeAngle(
+ first_coordinate, node_info_list[turn_node], third_coordinate);
+ if (angle < std::numeric_limits<double>::epsilon())
+ has_uturn_edge = true;
+ }
+
+ intersection.push_back(ConnectedRoad(
+ TurnOperation{onto_edge, angle, {TurnType::Invalid, DirectionModifier::UTurn}},
+ turn_is_valid));
+ }
+
+ // We hit the case of a street leading into nothing-ness. Since the code here assumes that this
+ // will
+ // never happen we add an artificial invalid uturn in this case.
+ if (!has_uturn_edge)
+ {
+ intersection.push_back(
+ {TurnOperation{via_eid, 0., {TurnType::Invalid, DirectionModifier::UTurn}}, false});
+ }
+
+ const auto ByAngle = [](const ConnectedRoad &first, const ConnectedRoad second) {
+ return first.turn.angle < second.turn.angle;
+ };
+ std::sort(std::begin(intersection), std::end(intersection), ByAngle);
+
+ BOOST_ASSERT(intersection[0].turn.angle >= 0. &&
+ intersection[0].turn.angle < std::numeric_limits<double>::epsilon());
+
+ return mergeSegregatedRoads(std::move(intersection));
+}
+
+/*
+ * Segregated Roads often merge onto a single intersection.
+ * While technically representing different roads, they are
+ * often looked at as a single road.
+ * Due to the merging, turn Angles seem off, wenn we compute them from the
+ * initial positions.
+ *
+ * b<b<b<b(1)<b<b<b
+ * aaaaa-b
+ * b>b>b>b(2)>b>b>b
+ *
+ * Would be seen as a slight turn going fro a to (2). A Sharp turn going from
+ * (1) to (2).
+ *
+ * In cases like these, we megre this segregated roads into a single road to
+ * end up with a case like:
+ *
+ * aaaaa-bbbbbb
+ *
+ * for the turn representation.
+ * Anything containing the first u-turn in a merge affects all other angles
+ * and is handled separately from all others.
+ */
+Intersection IntersectionGenerator::mergeSegregatedRoads(Intersection intersection) const
+{
+ const auto getRight = [&](std::size_t index) {
+ return (index + intersection.size() - 1) % intersection.size();
+ };
+
+ const auto mergable = [&](std::size_t first, std::size_t second) -> bool {
+ const auto &first_data = node_based_graph.GetEdgeData(intersection[first].turn.eid);
+ const auto &second_data = node_based_graph.GetEdgeData(intersection[second].turn.eid);
+
+ return first_data.name_id != INVALID_NAME_ID && first_data.name_id == second_data.name_id &&
+ !first_data.roundabout && !second_data.roundabout &&
+ first_data.travel_mode == second_data.travel_mode &&
+ first_data.road_classification == second_data.road_classification &&
+ // compatible threshold
+ angularDeviation(intersection[first].turn.angle, intersection[second].turn.angle) <
+ 60 &&
+ first_data.reversed != second_data.reversed;
+ };
+
+ const auto merge = [](const ConnectedRoad &first,
+ const ConnectedRoad &second) -> ConnectedRoad {
+ if (!first.entry_allowed)
+ {
+ ConnectedRoad result = second;
+ result.turn.angle = (first.turn.angle + second.turn.angle) / 2;
+ if (first.turn.angle - second.turn.angle > 180)
+ result.turn.angle += 180;
+ if (result.turn.angle > 360)
+ result.turn.angle -= 360;
+
+ return result;
+ }
+ else
+ {
+ BOOST_ASSERT(!second.entry_allowed);
+ ConnectedRoad result = first;
+ result.turn.angle = (first.turn.angle + second.turn.angle) / 2;
+
+ if (first.turn.angle - second.turn.angle > 180)
+ result.turn.angle += 180;
+ if (result.turn.angle > 360)
+ result.turn.angle -= 360;
+
+ return result;
+ }
+ };
+ if (intersection.size() == 1)
+ return intersection;
+
+ // check for merges including the basic u-turn
+ // these result in an adjustment of all other angles
+ if (mergable(0, intersection.size() - 1))
+ {
+ const double correction_factor =
+ (360 - intersection[intersection.size() - 1].turn.angle) / 2;
+ for (std::size_t i = 1; i + 1 < intersection.size(); ++i)
+ intersection[i].turn.angle += correction_factor;
+ intersection[0] = merge(intersection.front(), intersection.back());
+ intersection[0].turn.angle = 0;
+ intersection.pop_back();
+ }
+
+ else if (mergable(0, 1))
+ {
+ const double correction_factor = (intersection[1].turn.angle) / 2;
+ for (std::size_t i = 2; i < intersection.size(); ++i)
+ intersection[i].turn.angle += correction_factor;
+ intersection[0] = merge(intersection[0], intersection[1]);
+ intersection[0].turn.angle = 0;
+ intersection.erase(intersection.begin() + 1);
+ }
+
+ // a merge including the first u-turn requres an adjustment of the turn angles
+ // therefore these are handled prior to this step
+ for (std::size_t index = 2; index < intersection.size(); ++index)
+ {
+ if (mergable(index, getRight(index)))
+ {
+ intersection[getRight(index)] =
+ merge(intersection[getRight(index)], intersection[index]);
+ intersection.erase(intersection.begin() + index);
+ --index;
+ }
+ }
+
+ const auto ByAngle = [](const ConnectedRoad &first, const ConnectedRoad second) {
+ return first.turn.angle < second.turn.angle;
+ };
+ std::sort(std::begin(intersection), std::end(intersection), ByAngle);
+ return intersection;
+}
+
+} // namespace guidance
+} // namespace extractor
+} // namespace osrm
diff --git a/src/extractor/guidance/intersection_handler.cpp b/src/extractor/guidance/intersection_handler.cpp
new file mode 100644
index 0000000..b77f4ed
--- /dev/null
+++ b/src/extractor/guidance/intersection_handler.cpp
@@ -0,0 +1,307 @@
+#include "extractor/guidance/constants.hpp"
+#include "extractor/guidance/intersection_handler.hpp"
+#include "extractor/guidance/toolkit.hpp"
+
+#include <algorithm>
+
+using EdgeData = osrm::util::NodeBasedDynamicGraph::EdgeData;
+
+namespace osrm
+{
+namespace extractor
+{
+namespace guidance
+{
+
+namespace detail
+{
+inline bool requiresAnnouncement(const EdgeData &from, const EdgeData &to)
+{
+ return !from.IsCompatibleTo(to);
+}
+}
+
+IntersectionHandler::IntersectionHandler(const util::NodeBasedDynamicGraph &node_based_graph,
+ const std::vector<QueryNode> &node_info_list,
+ const util::NameTable &name_table)
+ : node_based_graph(node_based_graph), node_info_list(node_info_list), name_table(name_table)
+{
+}
+
+IntersectionHandler::~IntersectionHandler() {}
+
+std::size_t IntersectionHandler::countValid(const Intersection &intersection) const
+{
+ return std::count_if(intersection.begin(), intersection.end(),
+ [](const ConnectedRoad &road) { return road.entry_allowed; });
+}
+
+TurnType IntersectionHandler::findBasicTurnType(const EdgeID via_edge,
+ const ConnectedRoad &road) const
+{
+
+ const auto &in_data = node_based_graph.GetEdgeData(via_edge);
+ const auto &out_data = node_based_graph.GetEdgeData(road.turn.eid);
+
+ bool on_ramp = isRampClass(in_data.road_classification.road_class);
+
+ bool onto_ramp = isRampClass(out_data.road_classification.road_class);
+
+ if (!on_ramp && onto_ramp)
+ return TurnType::Ramp;
+
+ if (in_data.name_id == out_data.name_id && in_data.name_id != INVALID_NAME_ID)
+ {
+ return TurnType::Continue;
+ }
+
+ return TurnType::Turn;
+}
+
+TurnInstruction IntersectionHandler::getInstructionForObvious(const std::size_t num_roads,
+ const EdgeID via_edge,
+ const bool through_street,
+ const ConnectedRoad &road) const
+{
+ const auto type = findBasicTurnType(via_edge, road);
+ // handle travel modes:
+ const auto in_mode = node_based_graph.GetEdgeData(via_edge).travel_mode;
+ const auto out_mode = node_based_graph.GetEdgeData(road.turn.eid).travel_mode;
+ if (type == TurnType::Ramp)
+ {
+ return {TurnType::Ramp, getTurnDirection(road.turn.angle)};
+ }
+
+ if (angularDeviation(road.turn.angle, 0) < 0.01)
+ {
+ return {TurnType::Turn, DirectionModifier::UTurn};
+ }
+ if (type == TurnType::Turn)
+ {
+ const auto &in_data = node_based_graph.GetEdgeData(via_edge);
+ const auto &out_data = node_based_graph.GetEdgeData(road.turn.eid);
+ if (in_data.name_id != out_data.name_id &&
+ requiresNameAnnounced(name_table.GetNameForID(in_data.name_id),
+ name_table.GetNameForID(out_data.name_id)))
+ {
+ // obvious turn onto a through street is a merge
+ if (through_street)
+ {
+ return {TurnType::Merge, road.turn.angle > STRAIGHT_ANGLE
+ ? DirectionModifier::SlightRight
+ : DirectionModifier::SlightLeft};
+ }
+ else
+ {
+ return {TurnType::NewName, getTurnDirection(road.turn.angle)};
+ }
+ }
+ else
+ {
+ if (in_mode == out_mode)
+ return {TurnType::Suppressed, getTurnDirection(road.turn.angle)};
+ else
+ return {TurnType::Notification, getTurnDirection(road.turn.angle)};
+ }
+ }
+ BOOST_ASSERT(type == TurnType::Continue);
+ if (in_mode != out_mode)
+ {
+ return {TurnType::Notification, getTurnDirection(road.turn.angle)};
+ }
+ if (num_roads > 2)
+ {
+ return {TurnType::Suppressed, getTurnDirection(road.turn.angle)};
+ }
+ else
+ {
+ return {TurnType::NoTurn, getTurnDirection(road.turn.angle)};
+ }
+}
+
+void IntersectionHandler::assignFork(const EdgeID via_edge,
+ ConnectedRoad &left,
+ ConnectedRoad &right) const
+{
+ const auto &in_data = node_based_graph.GetEdgeData(via_edge);
+ const bool low_priority_left = isLowPriorityRoadClass(
+ node_based_graph.GetEdgeData(left.turn.eid).road_classification.road_class);
+ const bool low_priority_right = isLowPriorityRoadClass(
+ node_based_graph.GetEdgeData(right.turn.eid).road_classification.road_class);
+ if ((angularDeviation(left.turn.angle, STRAIGHT_ANGLE) < MAXIMAL_ALLOWED_NO_TURN_DEVIATION &&
+ angularDeviation(right.turn.angle, STRAIGHT_ANGLE) > FUZZY_ANGLE_DIFFERENCE))
+ {
+ // left side is actually straight
+ const auto &out_data = node_based_graph.GetEdgeData(left.turn.eid);
+ if (detail::requiresAnnouncement(in_data, out_data))
+ {
+ if (low_priority_right && !low_priority_left)
+ {
+ left.turn.instruction = getInstructionForObvious(3, via_edge, false, left);
+ right.turn.instruction = {findBasicTurnType(via_edge, right),
+ DirectionModifier::SlightRight};
+ }
+ else
+ {
+ if (low_priority_left && !low_priority_right)
+ {
+ left.turn.instruction = {findBasicTurnType(via_edge, left),
+ DirectionModifier::SlightLeft};
+ right.turn.instruction = {findBasicTurnType(via_edge, right),
+ DirectionModifier::SlightRight};
+ }
+ else
+ {
+ left.turn.instruction = {TurnType::Fork, DirectionModifier::SlightLeft};
+ right.turn.instruction = {TurnType::Fork, DirectionModifier::SlightRight};
+ }
+ }
+ }
+ else
+ {
+ left.turn.instruction = {TurnType::Suppressed, DirectionModifier::Straight};
+ right.turn.instruction = {findBasicTurnType(via_edge, right),
+ DirectionModifier::SlightRight};
+ }
+ }
+ else if (angularDeviation(right.turn.angle, STRAIGHT_ANGLE) <
+ MAXIMAL_ALLOWED_NO_TURN_DEVIATION &&
+ angularDeviation(left.turn.angle, STRAIGHT_ANGLE) > FUZZY_ANGLE_DIFFERENCE)
+ {
+ // right side is actually straight
+ const auto &out_data = node_based_graph.GetEdgeData(right.turn.eid);
+ if (angularDeviation(right.turn.angle, STRAIGHT_ANGLE) <
+ MAXIMAL_ALLOWED_NO_TURN_DEVIATION &&
+ angularDeviation(left.turn.angle, STRAIGHT_ANGLE) > FUZZY_ANGLE_DIFFERENCE)
+ {
+ if (detail::requiresAnnouncement(in_data, out_data))
+ {
+ if (low_priority_left && !low_priority_right)
+ {
+ left.turn.instruction = {findBasicTurnType(via_edge, left),
+ DirectionModifier::SlightLeft};
+ right.turn.instruction = getInstructionForObvious(3, via_edge, false, right);
+ }
+ else
+ {
+ if (low_priority_right && !low_priority_left)
+ {
+ left.turn.instruction = {findBasicTurnType(via_edge, left),
+ DirectionModifier::SlightLeft};
+ right.turn.instruction = {findBasicTurnType(via_edge, right),
+ DirectionModifier::SlightRight};
+ }
+ else
+ {
+ right.turn.instruction = {TurnType::Fork, DirectionModifier::SlightRight};
+ left.turn.instruction = {TurnType::Fork, DirectionModifier::SlightLeft};
+ }
+ }
+ }
+ else
+ {
+ right.turn.instruction = {TurnType::Suppressed, DirectionModifier::Straight};
+ left.turn.instruction = {findBasicTurnType(via_edge, left),
+ DirectionModifier::SlightLeft};
+ }
+ }
+ }
+ // left side of fork
+ if (low_priority_right && !low_priority_left)
+ left.turn.instruction = {TurnType::Suppressed, DirectionModifier::SlightLeft};
+ else
+ {
+ if (low_priority_left && !low_priority_right)
+ left.turn.instruction = {TurnType::Turn, DirectionModifier::SlightLeft};
+ else
+ left.turn.instruction = {TurnType::Fork, DirectionModifier::SlightLeft};
+ }
+
+ // right side of fork
+ if (low_priority_left && !low_priority_right)
+ right.turn.instruction = {TurnType::Suppressed, DirectionModifier::SlightLeft};
+ else
+ {
+ if (low_priority_right && !low_priority_left)
+ right.turn.instruction = {TurnType::Turn, DirectionModifier::SlightRight};
+ else
+ right.turn.instruction = {TurnType::Fork, DirectionModifier::SlightRight};
+ }
+}
+
+void IntersectionHandler::assignFork(const EdgeID via_edge,
+ ConnectedRoad &left,
+ ConnectedRoad ¢er,
+ ConnectedRoad &right) const
+{
+ // TODO handle low priority road classes in a reasonable way
+ if (left.entry_allowed && center.entry_allowed && right.entry_allowed)
+ {
+ left.turn.instruction = {TurnType::Fork, DirectionModifier::SlightLeft};
+ if (angularDeviation(center.turn.angle, 180) < MAXIMAL_ALLOWED_NO_TURN_DEVIATION)
+ {
+ const auto &in_data = node_based_graph.GetEdgeData(via_edge);
+ const auto &out_data = node_based_graph.GetEdgeData(center.turn.eid);
+ if (detail::requiresAnnouncement(in_data, out_data))
+ {
+ center.turn.instruction = {TurnType::Fork, DirectionModifier::Straight};
+ }
+ else
+ {
+ center.turn.instruction = {TurnType::Suppressed, DirectionModifier::Straight};
+ }
+ }
+ else
+ {
+ center.turn.instruction = {TurnType::Fork, DirectionModifier::Straight};
+ }
+ right.turn.instruction = {TurnType::Fork, DirectionModifier::SlightRight};
+ }
+ else if (left.entry_allowed)
+ {
+ if (right.entry_allowed)
+ assignFork(via_edge, left, right);
+ else if (center.entry_allowed)
+ assignFork(via_edge, left, center);
+ else
+ left.turn.instruction = {findBasicTurnType(via_edge, left),
+ getTurnDirection(left.turn.angle)};
+ }
+ else if (right.entry_allowed)
+ {
+ if (center.entry_allowed)
+ assignFork(via_edge, center, right);
+ else
+ right.turn.instruction = {findBasicTurnType(via_edge, right),
+ getTurnDirection(right.turn.angle)};
+ }
+ else
+ {
+ if (center.entry_allowed)
+ center.turn.instruction = {findBasicTurnType(via_edge, center),
+ getTurnDirection(center.turn.angle)};
+ }
+}
+
+bool IntersectionHandler::isThroughStreet(const std::size_t index,
+ const Intersection &intersection) const
+{
+ if (node_based_graph.GetEdgeData(intersection[index].turn.eid).name_id == INVALID_NAME_ID)
+ return false;
+ for (const auto &road : intersection)
+ {
+ // a through street cannot start at our own position
+ if (road.turn.angle < std::numeric_limits<double>::epsilon())
+ continue;
+ if (angularDeviation(road.turn.angle, intersection[index].turn.angle) >
+ (STRAIGHT_ANGLE - NARROW_TURN_ANGLE) &&
+ node_based_graph.GetEdgeData(road.turn.eid).name_id ==
+ node_based_graph.GetEdgeData(intersection[index].turn.eid).name_id)
+ return true;
+ }
+ return false;
+}
+
+} // namespace guidance
+} // namespace extractor
+} // namespace osrm
diff --git a/src/extractor/guidance/motorway_handler.cpp b/src/extractor/guidance/motorway_handler.cpp
new file mode 100644
index 0000000..c855b21
--- /dev/null
+++ b/src/extractor/guidance/motorway_handler.cpp
@@ -0,0 +1,524 @@
+#include "extractor/guidance/constants.hpp"
+#include "extractor/guidance/motorway_handler.hpp"
+#include "extractor/guidance/toolkit.hpp"
+
+#include "util/simple_logger.hpp"
+
+#include <limits>
+#include <utility>
+
+#include <boost/assert.hpp>
+
+namespace osrm
+{
+namespace extractor
+{
+namespace guidance
+{
+namespace detail
+{
+inline bool isMotorwayClass(const FunctionalRoadClass road_class)
+{
+ return road_class == FunctionalRoadClass::MOTORWAY || road_class == FunctionalRoadClass::TRUNK;
+}
+
+inline bool isMotorwayClass(EdgeID eid, const util::NodeBasedDynamicGraph &node_based_graph)
+{
+ return isMotorwayClass(node_based_graph.GetEdgeData(eid).road_classification.road_class);
+}
+inline FunctionalRoadClass roadClass(const ConnectedRoad &road,
+ const util::NodeBasedDynamicGraph &graph)
+{
+ return graph.GetEdgeData(road.turn.eid).road_classification.road_class;
+}
+
+inline bool isRampClass(EdgeID eid, const util::NodeBasedDynamicGraph &node_based_graph)
+{
+ return isRampClass(node_based_graph.GetEdgeData(eid).road_classification.road_class);
+}
+}
+
+MotorwayHandler::MotorwayHandler(const util::NodeBasedDynamicGraph &node_based_graph,
+ const std::vector<QueryNode> &node_info_list,
+ const util::NameTable &name_table)
+ : IntersectionHandler(node_based_graph, node_info_list, name_table)
+{
+}
+
+MotorwayHandler::~MotorwayHandler() {}
+
+bool MotorwayHandler::canProcess(const NodeID,
+ const EdgeID via_eid,
+ const Intersection &intersection) const
+{
+ bool has_motorway = false;
+ bool has_normal_roads = false;
+
+ for (const auto &road : intersection)
+ {
+ const auto &out_data = node_based_graph.GetEdgeData(road.turn.eid);
+ // not merging or forking?
+ if (road.entry_allowed && angularDeviation(road.turn.angle, STRAIGHT_ANGLE) > 60)
+ return false;
+ else if (out_data.road_classification.road_class == FunctionalRoadClass::MOTORWAY ||
+ out_data.road_classification.road_class == FunctionalRoadClass::TRUNK)
+ {
+ if (road.entry_allowed)
+ has_motorway = true;
+ }
+ else if (!isRampClass(out_data.road_classification.road_class))
+ has_normal_roads = true;
+ }
+
+ if (has_normal_roads)
+ return false;
+
+ const auto &in_data = node_based_graph.GetEdgeData(via_eid);
+ return has_motorway ||
+ in_data.road_classification.road_class == FunctionalRoadClass::MOTORWAY ||
+ in_data.road_classification.road_class == FunctionalRoadClass::TRUNK;
+}
+
+Intersection MotorwayHandler::
+operator()(const NodeID, const EdgeID via_eid, Intersection intersection) const
+{
+ const auto &in_data = node_based_graph.GetEdgeData(via_eid);
+
+ // coming from motorway
+ if (detail::isMotorwayClass(in_data.road_classification.road_class))
+ {
+ return fromMotorway(via_eid, std::move(intersection));
+ }
+ else // coming from a ramp
+ {
+ return fromRamp(via_eid, std::move(intersection));
+ // ramp merging straight onto motorway
+ }
+}
+
+Intersection MotorwayHandler::fromMotorway(const EdgeID via_eid, Intersection intersection) const
+{
+ const auto &in_data = node_based_graph.GetEdgeData(via_eid);
+ BOOST_ASSERT(detail::isMotorwayClass(in_data.road_classification.road_class));
+
+ const auto countExitingMotorways = [this](const Intersection &intersection) {
+ unsigned count = 0;
+ for (const auto &road : intersection)
+ {
+ if (road.entry_allowed && detail::isMotorwayClass(road.turn.eid, node_based_graph))
+ ++count;
+ }
+ return count;
+ };
+
+ // find the angle that continues on our current highway
+ const auto getContinueAngle = [this, in_data](const Intersection &intersection) {
+ for (const auto &road : intersection)
+ {
+ const auto &out_data = node_based_graph.GetEdgeData(road.turn.eid);
+ if (road.turn.angle != 0 && in_data.name_id == out_data.name_id &&
+ in_data.name_id != INVALID_NAME_ID &&
+ detail::isMotorwayClass(out_data.road_classification.road_class))
+ return road.turn.angle;
+ }
+ return intersection[0].turn.angle;
+ };
+
+ const auto getMostLikelyContinue = [this, in_data](const Intersection &intersection) {
+ double angle = intersection[0].turn.angle;
+ double best = 180;
+ for (const auto &road : intersection)
+ {
+ const auto &out_data = node_based_graph.GetEdgeData(road.turn.eid);
+ if (detail::isMotorwayClass(out_data.road_classification.road_class) &&
+ angularDeviation(road.turn.angle, STRAIGHT_ANGLE) < best)
+ {
+ best = angularDeviation(road.turn.angle, STRAIGHT_ANGLE);
+ angle = road.turn.angle;
+ }
+ }
+ return angle;
+ };
+
+ const auto findBestContinue = [&]() {
+ const double continue_angle = getContinueAngle(intersection);
+ if (continue_angle != intersection[0].turn.angle)
+ return continue_angle;
+ else
+ return getMostLikelyContinue(intersection);
+ };
+
+ // find continue angle
+ const double continue_angle = findBestContinue();
+ // highway does not continue and has no obvious choice
+ if (continue_angle == intersection[0].turn.angle)
+ {
+ if (intersection.size() == 2)
+ {
+ // do not announce ramps at the end of a highway
+ intersection[1].turn.instruction = {TurnType::NoTurn,
+ getTurnDirection(intersection[1].turn.angle)};
+ }
+ else if (intersection.size() == 3)
+ {
+ // splitting ramp at the end of a highway
+ if (intersection[1].entry_allowed && intersection[2].entry_allowed)
+ {
+ assignFork(via_eid, intersection[2], intersection[1]);
+ }
+ else
+ {
+ // ending in a passing ramp
+ if (intersection[1].entry_allowed)
+ intersection[1].turn.instruction = {
+ TurnType::NoTurn, getTurnDirection(intersection[1].turn.angle)};
+ else
+ intersection[2].turn.instruction = {
+ TurnType::NoTurn, getTurnDirection(intersection[2].turn.angle)};
+ }
+ }
+ else if (intersection.size() == 4 &&
+ detail::roadClass(intersection[1], node_based_graph) ==
+ detail::roadClass(intersection[2], node_based_graph) &&
+ detail::roadClass(intersection[2], node_based_graph) ==
+ detail::roadClass(intersection[3], node_based_graph))
+ {
+ // tripple fork at the end
+ assignFork(via_eid, intersection[3], intersection[2], intersection[1]);
+ }
+
+ else if (countValid(intersection) > 0) // check whether turns exist at all
+ {
+ // FALLBACK, this should hopefully never be reached
+ util::SimpleLogger().Write(logDEBUG)
+ << "Fallback reached from motorway, no continue angle, " << intersection.size()
+ << " roads, " << countValid(intersection) << " valid ones.";
+ return fallback(std::move(intersection));
+ }
+ }
+ else
+ {
+ const unsigned exiting_motorways = countExitingMotorways(intersection);
+
+ if (exiting_motorways == 0)
+ {
+ // Ending in Ramp
+ for (auto &road : intersection)
+ {
+ if (road.entry_allowed)
+ {
+ BOOST_ASSERT(detail::isRampClass(road.turn.eid, node_based_graph));
+ road.turn.instruction =
+ TurnInstruction::SUPPRESSED(getTurnDirection(road.turn.angle));
+ }
+ }
+ }
+ else if (exiting_motorways == 1)
+ {
+ // normal motorway passing some ramps or mering onto another motorway
+ if (intersection.size() == 2)
+ {
+ BOOST_ASSERT(!detail::isRampClass(intersection[1].turn.eid, node_based_graph));
+
+ intersection[1].turn.instruction =
+ getInstructionForObvious(intersection.size(), via_eid,
+ isThroughStreet(1,intersection), intersection[1]);
+ }
+ else
+ {
+ // Normal Highway exit or merge
+ for (auto &road : intersection)
+ {
+ // ignore invalid uturns/other
+ if (!road.entry_allowed)
+ continue;
+
+ if (road.turn.angle == continue_angle)
+ {
+ road.turn.instruction = getInstructionForObvious(
+ intersection.size(), via_eid, isThroughStreet(1,intersection), road);
+ }
+ else if (road.turn.angle < continue_angle)
+ {
+ road.turn.instruction = {
+ detail::isRampClass(road.turn.eid, node_based_graph) ? TurnType::Ramp
+ : TurnType::Turn,
+ (road.turn.angle < 145) ? DirectionModifier::Right
+ : DirectionModifier::SlightRight};
+ }
+ else if (road.turn.angle > continue_angle)
+ {
+ road.turn.instruction = {
+ detail::isRampClass(road.turn.eid, node_based_graph) ? TurnType::Ramp
+ : TurnType::Turn,
+ (road.turn.angle > 215) ? DirectionModifier::Left
+ : DirectionModifier::SlightLeft};
+ }
+ }
+ }
+ }
+ // handle motorway forks
+ else if (exiting_motorways > 1)
+ {
+ if (exiting_motorways == 2 && intersection.size() == 2)
+ {
+ intersection[1].turn.instruction =
+ getInstructionForObvious(intersection.size(), via_eid,
+ isThroughStreet(1,intersection), intersection[1]);
+ util::SimpleLogger().Write(logDEBUG) << "Disabled U-Turn on a freeway";
+ intersection[0].entry_allowed = false; // UTURN on the freeway
+ }
+ else if (exiting_motorways == 2)
+ {
+ // standard fork
+ std::size_t first_valid = std::numeric_limits<std::size_t>::max(),
+ second_valid = std::numeric_limits<std::size_t>::max();
+ for (std::size_t i = 0; i < intersection.size(); ++i)
+ {
+ if (intersection[i].entry_allowed &&
+ detail::isMotorwayClass(intersection[i].turn.eid, node_based_graph))
+ {
+ if (first_valid < intersection.size())
+ {
+ second_valid = i;
+ break;
+ }
+ else
+ {
+ first_valid = i;
+ }
+ }
+ }
+ assignFork(via_eid, intersection[second_valid], intersection[first_valid]);
+ }
+ else if (exiting_motorways == 3)
+ {
+ // triple fork
+ std::size_t first_valid = std::numeric_limits<std::size_t>::max(),
+ second_valid = std::numeric_limits<std::size_t>::max(),
+ third_valid = std::numeric_limits<std::size_t>::max();
+ for (std::size_t i = 0; i < intersection.size(); ++i)
+ {
+ if (intersection[i].entry_allowed &&
+ detail::isMotorwayClass(intersection[i].turn.eid, node_based_graph))
+ {
+ if (second_valid < intersection.size())
+ {
+ third_valid = i;
+ break;
+ }
+ else if (first_valid < intersection.size())
+ {
+ second_valid = i;
+ }
+ else
+ {
+ first_valid = i;
+ }
+ }
+ }
+ assignFork(via_eid, intersection[third_valid], intersection[second_valid],
+ intersection[first_valid]);
+ }
+ else
+ {
+ util::SimpleLogger().Write(logDEBUG) << "Found motorway junction with more than "
+ "2 exiting motorways or additional ramps";
+ return fallback(std::move(intersection));
+ }
+ } // done for more than one highway exit
+ }
+ return intersection;
+}
+
+Intersection MotorwayHandler::fromRamp(const EdgeID via_eid, Intersection intersection) const
+{
+ auto num_valid_turns = countValid(intersection);
+ // ramp straight into a motorway/ramp
+ if (intersection.size() == 2 && num_valid_turns == 1)
+ {
+ BOOST_ASSERT(!intersection[0].entry_allowed);
+ BOOST_ASSERT(detail::isMotorwayClass(intersection[1].turn.eid, node_based_graph));
+
+ intersection[1].turn.instruction = getInstructionForObvious(
+ intersection.size(), via_eid, isThroughStreet(1,intersection), intersection[1]);
+ }
+ else if (intersection.size() == 3)
+ {
+ // merging onto a passing highway / or two ramps merging onto the same highway
+ if (num_valid_turns == 1)
+ {
+ BOOST_ASSERT(!intersection[0].entry_allowed);
+ // check order of highways
+ // 4
+ // 5 3
+ //
+ // 6 2
+ //
+ // 7 1
+ // 0
+ if (intersection[1].entry_allowed)
+ {
+ if (detail::isMotorwayClass(intersection[1].turn.eid, node_based_graph) &&
+ node_based_graph.GetEdgeData(intersection[2].turn.eid).name_id !=
+ INVALID_NAME_ID &&
+ node_based_graph.GetEdgeData(intersection[2].turn.eid).name_id ==
+ node_based_graph.GetEdgeData(intersection[1].turn.eid).name_id)
+ {
+ // circular order indicates a merge to the left (0-3 onto 4
+ if (angularDeviation(intersection[1].turn.angle, STRAIGHT_ANGLE) <
+ NARROW_TURN_ANGLE)
+ intersection[1].turn.instruction = {TurnType::Merge,
+ DirectionModifier::SlightLeft};
+ else // fallback
+ intersection[1].turn.instruction = {
+ TurnType::Merge, getTurnDirection(intersection[1].turn.angle)};
+ }
+ else // passing by the end of a motorway
+ {
+ intersection[1].turn.instruction =
+ getInstructionForObvious(intersection.size(), via_eid,
+ isThroughStreet(1,intersection), intersection[1]);
+ }
+ }
+ else
+ {
+ BOOST_ASSERT(intersection[2].entry_allowed);
+ if (detail::isMotorwayClass(intersection[2].turn.eid, node_based_graph) &&
+ node_based_graph.GetEdgeData(intersection[1].turn.eid).name_id !=
+ INVALID_NAME_ID &&
+ node_based_graph.GetEdgeData(intersection[1].turn.eid).name_id ==
+ node_based_graph.GetEdgeData(intersection[0].turn.eid).name_id)
+ {
+ // circular order (5-0) onto 4
+ if (angularDeviation(intersection[2].turn.angle, STRAIGHT_ANGLE) <
+ NARROW_TURN_ANGLE)
+ intersection[2].turn.instruction = {TurnType::Merge,
+ DirectionModifier::SlightRight};
+ else // fallback
+ intersection[2].turn.instruction = {
+ TurnType::Merge, getTurnDirection(intersection[2].turn.angle)};
+ }
+ else // passing the end of a highway
+ {
+ intersection[2].turn.instruction =
+ getInstructionForObvious(intersection.size(), via_eid,
+ isThroughStreet(2,intersection), intersection[2]);
+ }
+ }
+ }
+ else
+ {
+ BOOST_ASSERT(num_valid_turns == 2);
+ // UTurn on ramps is not possible
+ BOOST_ASSERT(!intersection[0].entry_allowed);
+ BOOST_ASSERT(intersection[1].entry_allowed);
+ BOOST_ASSERT(intersection[2].entry_allowed);
+ // two motorways starting at end of ramp (fork)
+ // M M
+ // \ /
+ // |
+ // R
+ if (detail::isMotorwayClass(intersection[1].turn.eid, node_based_graph) &&
+ detail::isMotorwayClass(intersection[2].turn.eid, node_based_graph))
+ {
+ assignFork(via_eid, intersection[2], intersection[1]);
+ }
+ else
+ {
+ // continued ramp passing motorway entry
+ // M R
+ // M R
+ // | /
+ // R
+ if (detail::isMotorwayClass(node_based_graph.GetEdgeData(intersection[1].turn.eid)
+ .road_classification.road_class))
+ {
+ intersection[1].turn.instruction = {TurnType::Turn,
+ DirectionModifier::SlightRight};
+ intersection[2].turn.instruction = {TurnType::Continue,
+ DirectionModifier::SlightLeft};
+ }
+ else
+ {
+ assignFork(via_eid, intersection[2], intersection[1]);
+ }
+ }
+ }
+ }
+ // On - Off Ramp on passing Motorway, Ramp onto Fork(?)
+ else if (intersection.size() == 4)
+ {
+ bool passed_highway_entry = false;
+ for (auto &road : intersection)
+ {
+ const auto &edge_data = node_based_graph.GetEdgeData(road.turn.eid);
+ if (!road.entry_allowed &&
+ detail::isMotorwayClass(edge_data.road_classification.road_class))
+ {
+ passed_highway_entry = true;
+ }
+ else if (detail::isMotorwayClass(edge_data.road_classification.road_class))
+ {
+ road.turn.instruction = {TurnType::Merge, passed_highway_entry
+ ? DirectionModifier::SlightRight
+ : DirectionModifier::SlightLeft};
+ }
+ else
+ {
+ BOOST_ASSERT(isRampClass(edge_data.road_classification.road_class));
+ road.turn.instruction = {TurnType::Ramp, getTurnDirection(road.turn.angle)};
+ }
+ }
+ }
+ else
+ { // FALLBACK, hopefully this should never been reached
+ util::SimpleLogger().Write(logDEBUG) << "Reached fallback on motorway ramp with "
+ << intersection.size() << " roads and "
+ << countValid(intersection) << " valid turns.";
+ return fallback(std::move(intersection));
+ }
+ return intersection;
+}
+
+Intersection MotorwayHandler::fallback(Intersection intersection) const
+{
+ for (auto &road : intersection)
+ {
+ const auto &out_data = node_based_graph.GetEdgeData(road.turn.eid);
+
+ util::SimpleLogger().Write(logDEBUG)
+ << "road: " << toString(road) << " Name: " << out_data.name_id
+ << " Road Class: " << (int)out_data.road_classification.road_class;
+
+ if (!road.entry_allowed)
+ continue;
+
+ const auto type = detail::isMotorwayClass(out_data.road_classification.road_class)
+ ? TurnType::Merge
+ : TurnType::Turn;
+
+ if (type == TurnType::Turn)
+ {
+ if (angularDeviation(road.turn.angle, STRAIGHT_ANGLE) < FUZZY_ANGLE_DIFFERENCE)
+ road.turn.instruction = {type, DirectionModifier::Straight};
+ else
+ {
+ road.turn.instruction = {type, road.turn.angle > STRAIGHT_ANGLE
+ ? DirectionModifier::SlightLeft
+ : DirectionModifier::SlightRight};
+ }
+ }
+ else
+ {
+ road.turn.instruction = {type, road.turn.angle < STRAIGHT_ANGLE
+ ? DirectionModifier::SlightLeft
+ : DirectionModifier::SlightRight};
+ }
+ }
+ return intersection;
+}
+
+} // namespace guidance
+} // namespace extractor
+} // namespace osrm
diff --git a/src/extractor/guidance/roundabout_handler.cpp b/src/extractor/guidance/roundabout_handler.cpp
new file mode 100644
index 0000000..6bd72dc
--- /dev/null
+++ b/src/extractor/guidance/roundabout_handler.cpp
@@ -0,0 +1,257 @@
+#include "extractor/guidance/constants.hpp"
+#include "extractor/guidance/roundabout_handler.hpp"
+#include "extractor/guidance/toolkit.hpp"
+
+#include "util/simple_logger.hpp"
+
+#include <cmath>
+#include <set>
+#include <unordered_set>
+
+#include <boost/assert.hpp>
+
+namespace osrm
+{
+namespace extractor
+{
+namespace guidance
+{
+
+RoundaboutHandler::RoundaboutHandler(const util::NodeBasedDynamicGraph &node_based_graph,
+ const std::vector<QueryNode> &node_info_list,
+ const util::NameTable &name_table)
+ : IntersectionHandler(node_based_graph, node_info_list, name_table)
+{
+}
+
+RoundaboutHandler::~RoundaboutHandler() {}
+
+bool RoundaboutHandler::canProcess(const NodeID from_nid,
+ const EdgeID via_eid,
+ const Intersection &intersection) const
+{
+ const auto flags = getRoundaboutFlags(from_nid, via_eid, intersection);
+ return flags.on_roundabout || flags.can_enter;
+}
+
+Intersection RoundaboutHandler::
+operator()(const NodeID from_nid, const EdgeID via_eid, Intersection intersection) const
+{
+ const auto flags = getRoundaboutFlags(from_nid, via_eid, intersection);
+ const bool is_rotary = isRotary(node_based_graph.GetTarget(via_eid));
+ // find the radius of the roundabout
+ return handleRoundabouts(is_rotary, via_eid, flags.on_roundabout, flags.can_exit_separately,
+ std::move(intersection));
+}
+
+detail::RoundaboutFlags RoundaboutHandler::getRoundaboutFlags(
+ const NodeID from_nid, const EdgeID via_eid, const Intersection &intersection) const
+{
+ const auto &in_edge_data = node_based_graph.GetEdgeData(via_eid);
+ bool on_roundabout = in_edge_data.roundabout;
+ bool can_enter_roundabout = false;
+ bool can_exit_roundabout_separately = false;
+ for (const auto &road : intersection)
+ {
+ const auto &edge_data = node_based_graph.GetEdgeData(road.turn.eid);
+ // only check actual outgoing edges
+ if (edge_data.reversed)
+ continue;
+
+ if (edge_data.roundabout)
+ {
+ can_enter_roundabout = true;
+ }
+ // Exiting roundabouts at an entry point is technically a data-modelling issue.
+ // This workaround handles cases in which an exit follows the entry.
+ // To correctly represent perceived exits, we only count exits leading to a
+ // separate vertex than the one we are coming from that are in the direction of
+ // the roundabout.
+ // The sorting of the angles represents a problem for left-sided driving, though.
+ // FIXME in case of left-sided driving, we have to check whether we can enter the
+ // roundabout later in the cycle, rather than prior.
+ // FIXME requires consideration of crossing the roundabout
+ else if (node_based_graph.GetTarget(road.turn.eid) != from_nid && !can_enter_roundabout)
+ {
+ can_exit_roundabout_separately = true;
+ }
+ }
+ return {on_roundabout, can_enter_roundabout, can_exit_roundabout_separately};
+}
+
+bool RoundaboutHandler::isRotary(const NodeID nid) const
+{
+ // translate a node ID into its respective coordinate stored in the node_info_list
+ const auto getCoordinate = [this](const NodeID node) {
+ return util::Coordinate(node_info_list[node].lon, node_info_list[node].lat);
+ };
+
+ unsigned roundabout_name_id = 0;
+ std::unordered_set<unsigned> connected_names;
+
+ const auto getNextOnRoundabout = [this, &roundabout_name_id,
+ &connected_names](const NodeID node) {
+ EdgeID continue_edge = SPECIAL_EDGEID;
+ for (const auto edge : node_based_graph.GetAdjacentEdgeRange(node))
+ {
+ const auto &edge_data = node_based_graph.GetEdgeData(edge);
+ if (!edge_data.reversed && edge_data.roundabout)
+ {
+ if (SPECIAL_EDGEID != continue_edge)
+ {
+ // fork in roundabout
+ 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)))
+ {
+ return SPECIAL_EDGEID;
+ }
+
+ roundabout_name_id = edge_data.name_id;
+
+ continue_edge = edge;
+ }
+ else if (!edge_data.roundabout)
+ {
+ // remember all connected road names
+ connected_names.insert(edge_data.name_id);
+ }
+ }
+ return continue_edge;
+ };
+ // the roundabout radius has to be the same for all locations we look at it from
+ // to guarantee this, we search the full roundabout for its vertices
+ // and select the three smalles ids
+ std::set<NodeID> roundabout_nodes; // needs to be sorted
+
+ // this value is a hard abort to deal with potential self-loops
+ NodeID last_node = nid;
+ while (0 == roundabout_nodes.count(last_node))
+ {
+ roundabout_nodes.insert(last_node);
+ const auto eid = getNextOnRoundabout(last_node);
+
+ if (eid == SPECIAL_EDGEID)
+ {
+ util::SimpleLogger().Write(logDEBUG) << "Non-Loop Roundabout found.";
+ return false;
+ }
+
+ last_node = node_based_graph.GetTarget(eid);
+ }
+
+ // do we have a dedicated name for the rotary, if not its a roundabout
+ // This function can theoretically fail if the roundabout name is partly
+ // used with a reference and without. This will be fixed automatically
+ // when we handle references separately or if the useage is more consistent
+ if (roundabout_name_id == 0 || connected_names.count(roundabout_name_id))
+ {
+ return false;
+ }
+
+ if (roundabout_nodes.size() <= 1)
+ {
+ return false;
+ }
+ // calculate the radius of the roundabout/rotary. For two coordinates, we assume a minimal
+ // circle
+ // with both vertices right at the other side (so half their distance in meters).
+ // Otherwise, we construct a circle through the first tree vertices.
+ const auto getRadius = [&roundabout_nodes, &getCoordinate]() {
+ auto node_itr = roundabout_nodes.begin();
+ if (roundabout_nodes.size() == 2)
+ {
+ const auto first = getCoordinate(*node_itr++), second = getCoordinate(*node_itr++);
+ return 0.5 * util::coordinate_calculation::haversineDistance(first, second);
+ }
+ else
+ {
+ const auto first = getCoordinate(*node_itr++), second = getCoordinate(*node_itr++),
+ third = getCoordinate(*node_itr++);
+ return util::coordinate_calculation::circleRadius(first, second, third);
+ }
+ };
+ const double radius = getRadius();
+
+ // check whether the circle computation has gone wrong
+ // The radius computation can result in infinity, if the three coordinates are non-distinct.
+ // To stay on the safe side, we say its not a rotary
+ if (std::isinf(radius))
+ return false;
+
+ return radius > MAX_ROUNDABOUT_RADIUS;
+}
+
+Intersection RoundaboutHandler::handleRoundabouts(const bool is_rotary,
+ const EdgeID via_eid,
+ const bool on_roundabout,
+ const bool can_exit_roundabout_separately,
+ Intersection intersection) const
+{
+ // TODO requires differentiation between roundabouts and rotaries
+ // detect via radius (get via circle through three vertices)
+ NodeID node_v = node_based_graph.GetTarget(via_eid);
+ if (on_roundabout)
+ {
+ // Shoule hopefully have only a single exit and continue
+ // at least for cars. How about bikes?
+ for (auto &road : intersection)
+ {
+ auto &turn = road.turn;
+ const auto &out_data = node_based_graph.GetEdgeData(road.turn.eid);
+ if (out_data.roundabout)
+ {
+ // TODO can forks happen in roundabouts? E.g. required lane changes
+ if (1 == node_based_graph.GetDirectedOutDegree(node_v))
+ {
+ // No turn possible.
+ turn.instruction = TurnInstruction::NO_TURN();
+ }
+ else
+ {
+ turn.instruction =
+ TurnInstruction::REMAIN_ROUNDABOUT(is_rotary, getTurnDirection(turn.angle));
+ }
+ }
+ else
+ {
+ turn.instruction =
+ TurnInstruction::EXIT_ROUNDABOUT(is_rotary, getTurnDirection(turn.angle));
+ }
+ }
+ return intersection;
+ }
+ else
+ for (auto &road : intersection)
+ {
+ if (!road.entry_allowed)
+ continue;
+ auto &turn = road.turn;
+ const auto &out_data = node_based_graph.GetEdgeData(turn.eid);
+ if (out_data.roundabout)
+ {
+ turn.instruction =
+ TurnInstruction::ENTER_ROUNDABOUT(is_rotary, getTurnDirection(turn.angle));
+ if (can_exit_roundabout_separately)
+ {
+ if (turn.instruction.type == TurnType::EnterRotary)
+ turn.instruction.type = TurnType::EnterRotaryAtExit;
+ if (turn.instruction.type == TurnType::EnterRoundabout)
+ turn.instruction.type = TurnType::EnterRoundaboutAtExit;
+ }
+ }
+ else
+ {
+ turn.instruction = TurnInstruction::ENTER_AND_EXIT_ROUNDABOUT(
+ is_rotary, getTurnDirection(turn.angle));
+ }
+ }
+ return intersection;
+}
+
+} // namespace guidance
+} // namespace extractor
+} // namespace osrm
diff --git a/src/extractor/guidance/turn_analysis.cpp b/src/extractor/guidance/turn_analysis.cpp
index 0281e16..9413f87 100644
--- a/src/extractor/guidance/turn_analysis.cpp
+++ b/src/extractor/guidance/turn_analysis.cpp
@@ -1,11 +1,15 @@
+#include "extractor/guidance/constants.hpp"
#include "extractor/guidance/turn_analysis.hpp"
-#include "util/simple_logger.hpp"
#include "util/coordinate.hpp"
+#include "util/coordinate_calculation.hpp"
+#include "util/simple_logger.hpp"
#include <cstddef>
-#include <limits>
#include <iomanip>
+#include <limits>
+#include <set>
+#include <unordered_set>
namespace osrm
{
@@ -13,154 +17,54 @@ namespace extractor
{
namespace guidance
{
-// configuration of turn classification
-const bool constexpr INVERT = true;
-
-// what angle is interpreted as going straight
-const double constexpr STRAIGHT_ANGLE = 180.;
-// if a turn deviates this much from going straight, it will be kept straight
-const double constexpr MAXIMAL_ALLOWED_NO_TURN_DEVIATION = 3.;
-// angle that lies between two nearly indistinguishable roads
-const double constexpr NARROW_TURN_ANGLE = 30.;
-const double constexpr GROUP_ANGLE = 90;
-// angle difference that can be classified as straight, if its the only narrow turn
-const double constexpr FUZZY_ANGLE_DIFFERENCE = 15.;
-const double constexpr DISTINCTION_RATIO = 2;
-const unsigned constexpr INVALID_NAME_ID = 0;
using EdgeData = util::NodeBasedDynamicGraph::EdgeData;
-ConnectedRoad::ConnectedRoad(const TurnOperation turn, const bool entry_allowed)
- : turn(turn), entry_allowed(entry_allowed)
-{
-}
-
bool requiresAnnouncement(const EdgeData &from, const EdgeData &to)
{
return !from.IsCompatibleTo(to);
}
-struct Localizer
-{
- const std::vector<QueryNode> *node_info_list = nullptr;
-
- util::Coordinate operator()(const NodeID nid)
- {
- if (node_info_list)
- {
- return {(*node_info_list)[nid].lon, (*node_info_list)[nid].lat};
- }
- return {};
- }
-};
-
-static Localizer localizer;
-
TurnAnalysis::TurnAnalysis(const util::NodeBasedDynamicGraph &node_based_graph,
const std::vector<QueryNode> &node_info_list,
const RestrictionMap &restriction_map,
const std::unordered_set<NodeID> &barrier_nodes,
const CompressedEdgeContainer &compressed_edge_container,
const util::NameTable &name_table)
- : node_based_graph(node_based_graph), node_info_list(node_info_list),
- restriction_map(restriction_map), barrier_nodes(barrier_nodes),
- compressed_edge_container(compressed_edge_container), name_table(name_table)
+ : node_based_graph(node_based_graph), intersection_generator(node_based_graph,
+ restriction_map,
+ barrier_nodes,
+ node_info_list,
+ compressed_edge_container),
+ roundabout_handler(node_based_graph, node_info_list, name_table),
+ motorway_handler(node_based_graph, node_info_list, name_table),
+ turn_handler(node_based_graph, node_info_list, name_table)
{
}
-// some small tool functions to simplify decisions down the line
-namespace detail
+std::vector<TurnOperation> TurnAnalysis::getTurns(const NodeID from_nid, const EdgeID via_eid) const
{
+ auto intersection = intersection_generator(from_nid, via_eid);
-inline FunctionalRoadClass roadClass(const ConnectedRoad &road,
- const util::NodeBasedDynamicGraph &graph)
-{
- return graph.GetEdgeData(road.turn.eid).road_classification.road_class;
-}
-
-inline bool isMotorwayClass(FunctionalRoadClass road_class)
-{
- return road_class == FunctionalRoadClass::MOTORWAY || road_class == FunctionalRoadClass::TRUNK;
-}
-
-inline bool isMotorwayClass(EdgeID eid, const util::NodeBasedDynamicGraph &node_based_graph)
-{
- return isMotorwayClass(node_based_graph.GetEdgeData(eid).road_classification.road_class);
-}
-
-inline bool isRampClass(EdgeID eid, const util::NodeBasedDynamicGraph &node_based_graph)
-{
- return isRampClass(node_based_graph.GetEdgeData(eid).road_classification.road_class);
-}
-
-} // namespace detail
-
-std::vector<TurnOperation> TurnAnalysis::getTurns(const NodeID from, const EdgeID via_edge) const
-{
- localizer.node_info_list = &node_info_list;
- auto intersection = getConnectedRoads(from, via_edge);
-
- const auto &in_edge_data = node_based_graph.GetEdgeData(via_edge);
-
- // main priority: roundabouts
- bool on_roundabout = in_edge_data.roundabout;
- bool can_enter_roundabout = false;
- bool can_exit_roundabout_separately = false;
- for (const auto &road : intersection)
+ // Roundabouts are a main priority. If there is a roundabout instruction present, we process the
+ // turn as a roundabout
+ if (roundabout_handler.canProcess(from_nid, via_eid, intersection))
{
- const auto &edge_data = node_based_graph.GetEdgeData(road.turn.eid);
- // only check actual outgoing edges
- if (edge_data.reversed)
- continue;
-
- if (edge_data.roundabout)
- {
- can_enter_roundabout = true;
- }
- // Exiting roundabouts at an entry point is technically a data-modelling issue.
- // This workaround handles cases in which an exit follows the entry.
- // To correctly represent perceived exits, we only count exits leading to a
- // separate vertex than the one we are coming from that are in the direction of
- // the roundabout.
- // The sorting of the angles represents a problem for left-sided driving, though.
- // FIXME in case of left-sided driving, we have to check whether we can enter the
- // roundabout later in the cycle, rather than prior.
- else if (node_based_graph.GetTarget(road.turn.eid) != from && !can_enter_roundabout)
- {
- can_exit_roundabout_separately = true;
- }
- }
- if (on_roundabout || can_enter_roundabout)
- {
- intersection = handleRoundabouts(via_edge, on_roundabout, can_exit_roundabout_separately,
- std::move(intersection));
+ intersection = roundabout_handler(from_nid, via_eid, std::move(intersection));
}
else
{
// set initial defaults for normal turns and modifier based on angle
- intersection = setTurnTypes(from, via_edge, std::move(intersection));
- if (isMotorwayJunction(via_edge, intersection))
+ intersection = setTurnTypes(from_nid, via_eid, std::move(intersection));
+ if (motorway_handler.canProcess(from_nid, via_eid, intersection))
{
- intersection = handleMotorwayJunction(via_edge, std::move(intersection));
- }
-
- else if (intersection.size() == 1)
- {
- intersection = handleOneWayTurn(std::move(intersection));
- }
- else if (intersection.size() == 2)
- {
- intersection = handleTwoWayTurn(via_edge, std::move(intersection));
- }
- else if (intersection.size() == 3)
- {
- intersection = handleThreeWayTurn(via_edge, std::move(intersection));
+ intersection = motorway_handler(from_nid, via_eid, std::move(intersection));
}
else
{
- intersection = handleComplexTurn(via_edge, std::move(intersection));
+ BOOST_ASSERT(turn_handler.canProcess(from_nid, via_eid, intersection));
+ intersection = turn_handler(from_nid, via_eid, std::move(intersection));
}
- // complex intersection, potentially requires conflict resolution
}
std::vector<TurnOperation> turns;
@@ -171,2139 +75,22 @@ std::vector<TurnOperation> TurnAnalysis::getTurns(const NodeID from, const EdgeI
return turns;
}
-inline std::size_t countValid(const std::vector<ConnectedRoad> &intersection)
-{
- return std::count_if(intersection.begin(), intersection.end(), [](const ConnectedRoad &road)
- {
- return road.entry_allowed;
- });
-}
-
-std::vector<ConnectedRoad>
-TurnAnalysis::handleRoundabouts(const EdgeID via_edge,
- const bool on_roundabout,
- const bool can_exit_roundabout_separately,
- std::vector<ConnectedRoad> intersection) const
-{
- // TODO requires differentiation between roundabouts and rotaries
- // detect via radius (get via circle through three vertices)
- NodeID node_v = node_based_graph.GetTarget(via_edge);
- if (on_roundabout)
- {
- // Shoule hopefully have only a single exit and continue
- // at least for cars. How about bikes?
- for (auto &road : intersection)
- {
- auto &turn = road.turn;
- const auto &out_data = node_based_graph.GetEdgeData(road.turn.eid);
- if (out_data.roundabout)
- {
- // TODO can forks happen in roundabouts? E.g. required lane changes
- if (1 == node_based_graph.GetDirectedOutDegree(node_v))
- {
- // No turn possible.
- turn.instruction = TurnInstruction::NO_TURN();
- }
- else
- {
- turn.instruction =
- TurnInstruction::REMAIN_ROUNDABOUT(getTurnDirection(turn.angle));
- }
- }
- else
- {
- turn.instruction = TurnInstruction::EXIT_ROUNDABOUT(getTurnDirection(turn.angle));
- }
- }
- return intersection;
- }
- else
- {
- for (auto &road : intersection)
- {
- if (!road.entry_allowed)
- continue;
- auto &turn = road.turn;
- const auto &out_data = node_based_graph.GetEdgeData(turn.eid);
- if (out_data.roundabout)
- {
- turn.instruction = TurnInstruction::ENTER_ROUNDABOUT(getTurnDirection(turn.angle));
- if (can_exit_roundabout_separately)
- {
- if (turn.instruction.type == TurnType::EnterRotary)
- turn.instruction.type = TurnType::EnterRotaryAtExit;
- if (turn.instruction.type == TurnType::EnterRoundabout)
- turn.instruction.type = TurnType::EnterRoundaboutAtExit;
- }
- }
- else
- {
- turn.instruction = {TurnType::EnterAndExitRoundabout, getTurnDirection(turn.angle)};
- }
- }
- return intersection;
- }
-}
-
-std::vector<ConnectedRoad>
-TurnAnalysis::fallbackTurnAssignmentMotorway(std::vector<ConnectedRoad> intersection) const
+// Sets basic turn types as fallback for otherwise unhandled turns
+Intersection TurnAnalysis::setTurnTypes(const NodeID from_nid,
+ const EdgeID,
+ Intersection intersection) const
{
for (auto &road : intersection)
{
- const auto &out_data = node_based_graph.GetEdgeData(road.turn.eid);
-
- util::SimpleLogger().Write(logWARNING)
- << "road: " << road.toString() << " Name: " << out_data.name_id
- << " Road Class: " << (int)out_data.road_classification.road_class
- << " At: " << localizer(node_based_graph.GetTarget(road.turn.eid));
-
if (!road.entry_allowed)
continue;
- const auto type = detail::isMotorwayClass(out_data.road_classification.road_class)
- ? TurnType::Merge
- : TurnType::Turn;
- if (angularDeviation(road.turn.angle, STRAIGHT_ANGLE) < FUZZY_ANGLE_DIFFERENCE)
- road.turn.instruction = {type, DirectionModifier::Straight};
- else
- {
- road.turn.instruction = {type,
- road.turn.angle > STRAIGHT_ANGLE
- ? DirectionModifier::SlightLeft
- : DirectionModifier::SlightRight};
- }
- }
- return intersection;
-}
-
-std::vector<ConnectedRoad>
-TurnAnalysis::handleFromMotorway(const EdgeID via_edge,
- std::vector<ConnectedRoad> intersection) const
-{
- const auto &in_data = node_based_graph.GetEdgeData(via_edge);
- BOOST_ASSERT(detail::isMotorwayClass(in_data.road_classification.road_class));
-
- const auto countExitingMotorways = [this](const std::vector<ConnectedRoad> &intersection)
- {
- unsigned count = 0;
- for (const auto &road : intersection)
- {
- if (road.entry_allowed && detail::isMotorwayClass(road.turn.eid, node_based_graph))
- ++count;
- }
- return count;
- };
-
- // find the angle that continues on our current highway
- const auto getContinueAngle = [this, in_data](const std::vector<ConnectedRoad> &intersection)
- {
- for (const auto &road : intersection)
- {
- const auto &out_data = node_based_graph.GetEdgeData(road.turn.eid);
- if (road.turn.angle != 0 && in_data.name_id == out_data.name_id &&
- in_data.name_id != 0 &&
- detail::isMotorwayClass(out_data.road_classification.road_class))
- return road.turn.angle;
- }
- return intersection[0].turn.angle;
- };
-
- const auto getMostLikelyContinue =
- [this, in_data](const std::vector<ConnectedRoad> &intersection)
- {
- double angle = intersection[0].turn.angle;
- double best = 180;
- for (const auto &road : intersection)
- {
- const auto &out_data = node_based_graph.GetEdgeData(road.turn.eid);
- if (detail::isMotorwayClass(out_data.road_classification.road_class) &&
- angularDeviation(road.turn.angle, STRAIGHT_ANGLE) < best)
- {
- best = angularDeviation(road.turn.angle, STRAIGHT_ANGLE);
- angle = road.turn.angle;
- }
- }
- return angle;
- };
-
- const auto findBestContinue = [&]()
- {
- const double continue_angle = getContinueAngle(intersection);
- if (continue_angle != intersection[0].turn.angle)
- return continue_angle;
- else
- return getMostLikelyContinue(intersection);
- };
-
- // find continue angle
- const double continue_angle = findBestContinue();
-
- // highway does not continue and has no obvious choice
- if (continue_angle == intersection[0].turn.angle)
- {
- if (intersection.size() == 2)
- {
- // do not announce ramps at the end of a highway
- intersection[1].turn.instruction = {TurnType::NoTurn,
- getTurnDirection(intersection[1].turn.angle)};
- }
- else if (intersection.size() == 3)
- {
- // splitting ramp at the end of a highway
- if (intersection[1].entry_allowed && intersection[2].entry_allowed)
- {
- assignFork(via_edge, intersection[2], intersection[1]);
- }
- else
- {
- // ending in a passing ramp
- if (intersection[1].entry_allowed)
- intersection[1].turn.instruction = {
- TurnType::NoTurn, getTurnDirection(intersection[1].turn.angle)};
- else
- intersection[2].turn.instruction = {
- TurnType::NoTurn, getTurnDirection(intersection[2].turn.angle)};
- }
- }
- else if (intersection.size() == 4 &&
- detail::roadClass(intersection[1], node_based_graph) ==
- detail::roadClass(intersection[2], node_based_graph) &&
- detail::roadClass(intersection[2], node_based_graph) ==
- detail::roadClass(intersection[3], node_based_graph))
- {
- // tripple fork at the end
- assignFork(via_edge, intersection[3], intersection[2], intersection[1]);
- }
- else if (countValid(intersection) > 0) // check whether turns exist at all
- {
- // FALLBACK, this should hopefully never be reached
- auto coord = localizer(node_based_graph.GetTarget(via_edge));
- util::SimpleLogger().Write(logWARNING)
- << "Fallback reached from motorway at " << std::setprecision(12)
- << toFloating(coord.lat) << " " << toFloating(coord.lon) << ", no continue angle, "
- << intersection.size() << " roads, " << countValid(intersection) << " valid ones.";
- fallbackTurnAssignmentMotorway(intersection);
- }
- }
- else
- {
- const unsigned exiting_motorways = countExitingMotorways(intersection);
-
- if (exiting_motorways == 0)
- {
- // Ending in Ramp
- for (auto &road : intersection)
- {
- if (road.entry_allowed)
- {
- BOOST_ASSERT(detail::isRampClass(road.turn.eid, node_based_graph));
- road.turn.instruction =
- TurnInstruction::SUPPRESSED(getTurnDirection(road.turn.angle));
- }
- }
- }
- else if (exiting_motorways == 1)
- {
- // normal motorway passing some ramps or mering onto another motorway
- if (intersection.size() == 2)
- {
- BOOST_ASSERT(!detail::isRampClass(intersection[1].turn.eid, node_based_graph));
-
- intersection[1].turn.instruction =
- getInstructionForObvious(intersection.size(), via_edge, intersection[1]);
- }
- else
- {
- // continue on the same highway
- bool continues = (getContinueAngle(intersection) != intersection[0].turn.angle);
- // Normal Highway exit or merge
- for (auto &road : intersection)
- {
- // ignore invalid uturns/other
- if (!road.entry_allowed)
- continue;
-
- if (road.turn.angle == continue_angle)
- {
- if (continues)
- road.turn.instruction =
- TurnInstruction::SUPPRESSED(DirectionModifier::Straight);
- else // TODO handle turn direction correctly
- road.turn.instruction = {TurnType::Merge, DirectionModifier::Straight};
- }
- else if (road.turn.angle < continue_angle)
- {
- road.turn.instruction = {
- detail::isRampClass(road.turn.eid, node_based_graph) ? TurnType::Ramp
- : TurnType::Turn,
- (road.turn.angle < 145) ? DirectionModifier::Right
- : DirectionModifier::SlightRight};
- }
- else if (road.turn.angle > continue_angle)
- {
- road.turn.instruction = {
- detail::isRampClass(road.turn.eid, node_based_graph) ? TurnType::Ramp
- : TurnType::Turn,
- (road.turn.angle > 215) ? DirectionModifier::Left
- : DirectionModifier::SlightLeft};
- }
- }
- }
- }
- // handle motorway forks
- else if (exiting_motorways > 1)
- {
- if (exiting_motorways == 2 && intersection.size() == 2)
- {
- intersection[1].turn.instruction =
- getInstructionForObvious(intersection.size(), via_edge, intersection[1]);
- util::SimpleLogger().Write(logWARNING)
- << "Disabled U-Turn on a freeway at "
- << localizer(node_based_graph.GetTarget(via_edge));
- intersection[0].entry_allowed = false; // UTURN on the freeway
- }
- else if (exiting_motorways == 2)
- {
- // standard fork
- std::size_t first_valid = std::numeric_limits<std::size_t>::max(),
- second_valid = std::numeric_limits<std::size_t>::max();
- for (std::size_t i = 0; i < intersection.size(); ++i)
- {
- if (intersection[i].entry_allowed &&
- detail::isMotorwayClass(intersection[i].turn.eid, node_based_graph))
- {
- if (first_valid < intersection.size())
- {
- second_valid = i;
- break;
- }
- else
- {
- first_valid = i;
- }
- }
- }
- assignFork(via_edge, intersection[second_valid], intersection[first_valid]);
- }
- else if (exiting_motorways == 3)
- {
- // triple fork
- std::size_t first_valid = std::numeric_limits<std::size_t>::max(),
- second_valid = std::numeric_limits<std::size_t>::max(),
- third_valid = std::numeric_limits<std::size_t>::max();
- for (std::size_t i = 0; i < intersection.size(); ++i)
- {
- if (intersection[i].entry_allowed &&
- detail::isMotorwayClass(intersection[i].turn.eid, node_based_graph))
- {
- if (second_valid < intersection.size())
- {
- third_valid = i;
- break;
- }
- else if (first_valid < intersection.size())
- {
- second_valid = i;
- }
- else
- {
- first_valid = i;
- }
- }
- }
- assignFork(via_edge, intersection[third_valid], intersection[second_valid],
- intersection[first_valid]);
- }
- else
- {
- auto coord = localizer(node_based_graph.GetTarget(via_edge));
- util::SimpleLogger().Write(logWARNING)
- << "Found motorway junction with more than "
- "2 exiting motorways or additional ramps at " << std::setprecision(12)
- << toFloating(coord.lat) << " " << toFloating(coord.lon);
- fallbackTurnAssignmentMotorway(intersection);
- }
- } // done for more than one highway exit
- }
- return intersection;
-}
-
-std::vector<ConnectedRoad>
-TurnAnalysis::handleMotorwayRamp(const EdgeID via_edge,
- std::vector<ConnectedRoad> intersection) const
-{
- auto num_valid_turns = countValid(intersection);
- // ramp straight into a motorway/ramp
- if (intersection.size() == 2 && num_valid_turns == 1)
- {
- BOOST_ASSERT(!intersection[0].entry_allowed);
- BOOST_ASSERT(detail::isMotorwayClass(intersection[1].turn.eid, node_based_graph));
-
- intersection[1].turn.instruction =
- getInstructionForObvious(intersection.size(), via_edge, intersection[1]);
- }
- else if (intersection.size() == 3)
- {
- // merging onto a passing highway / or two ramps merging onto the same highway
- if (num_valid_turns == 1)
- {
- BOOST_ASSERT(!intersection[0].entry_allowed);
- // check order of highways
- // 4
- // 5 3
- //
- // 6 2
- //
- // 7 1
- // 0
- if (intersection[1].entry_allowed)
- {
- if (detail::isMotorwayClass(intersection[1].turn.eid, node_based_graph))
- {
- // circular order indicates a merge to the left (0-3 onto 4
- if (angularDeviation(intersection[1].turn.angle, STRAIGHT_ANGLE) <
- NARROW_TURN_ANGLE)
- intersection[1].turn.instruction = {TurnType::Merge,
- DirectionModifier::SlightLeft};
- else // fallback
- intersection[1].turn.instruction = {
- TurnType::Merge, getTurnDirection(intersection[1].turn.angle)};
- }
- else // passing by the end of a motorway
- intersection[1].turn.instruction =
- getInstructionForObvious(intersection.size(), via_edge, intersection[1]);
- }
- else
- {
- BOOST_ASSERT(intersection[2].entry_allowed);
- if (detail::isMotorwayClass(intersection[2].turn.eid, node_based_graph))
- {
- // circular order (5-0) onto 4
- if (angularDeviation(intersection[2].turn.angle, STRAIGHT_ANGLE) <
- NARROW_TURN_ANGLE)
- intersection[2].turn.instruction = {TurnType::Merge,
- DirectionModifier::SlightRight};
- else // fallback
- intersection[2].turn.instruction = {
- TurnType::Merge, getTurnDirection(intersection[2].turn.angle)};
- }
- else // passing the end of a highway
- intersection[1].turn.instruction =
- getInstructionForObvious(intersection.size(), via_edge, intersection[1]);
- }
- }
- else
- {
- BOOST_ASSERT(num_valid_turns == 2);
- // UTurn on ramps is not possible
- BOOST_ASSERT(!intersection[0].entry_allowed);
- BOOST_ASSERT(intersection[1].entry_allowed);
- BOOST_ASSERT(intersection[2].entry_allowed);
- // two motorways starting at end of ramp (fork)
- // M M
- // \ /
- // |
- // R
- if (detail::isMotorwayClass(intersection[1].turn.eid, node_based_graph) &&
- detail::isMotorwayClass(intersection[2].turn.eid, node_based_graph))
- {
- assignFork(via_edge, intersection[2], intersection[1]);
- }
- else
- {
- // continued ramp passing motorway entry
- // M R
- // M R
- // | /
- // R
- if (detail::isMotorwayClass(node_based_graph.GetEdgeData(intersection[1].turn.eid)
- .road_classification.road_class))
- {
- intersection[1].turn.instruction = {TurnType::Merge,
- DirectionModifier::SlightRight};
- intersection[2].turn.instruction = {TurnType::Fork,
- DirectionModifier::SlightLeft};
- }
- else
- {
- intersection[1].turn.instruction = {TurnType::Fork,
- DirectionModifier::SlightRight};
- intersection[2].turn.instruction = {TurnType::Merge,
- DirectionModifier::SlightLeft};
- }
- }
- }
- }
- // On - Off Ramp on passing Motorway, Ramp onto Fork(?)
- else if (intersection.size() == 4)
- {
- bool passed_highway_entry = false;
- for (auto &road : intersection)
- {
- const auto &edge_data = node_based_graph.GetEdgeData(road.turn.eid);
- if (!road.entry_allowed &&
- detail::isMotorwayClass(edge_data.road_classification.road_class))
- {
- passed_highway_entry = true;
- }
- else if (detail::isMotorwayClass(edge_data.road_classification.road_class))
- {
- road.turn.instruction = {TurnType::Merge,
- passed_highway_entry ? DirectionModifier::SlightRight
- : DirectionModifier::SlightLeft};
- }
- else
- {
- BOOST_ASSERT(isRampClass(edge_data.road_classification.road_class));
- road.turn.instruction = {TurnType::Ramp, getTurnDirection(road.turn.angle)};
- }
- }
- }
- else
- { // FALLBACK, hopefully this should never been reached
- util::SimpleLogger().Write(logWARNING) << "Reached fallback on motorway ramp with "
- << intersection.size() << " roads and "
- << countValid(intersection) << " valid turns.";
- fallbackTurnAssignmentMotorway(intersection);
- }
- return intersection;
-}
-
-std::vector<ConnectedRoad>
-TurnAnalysis::handleMotorwayJunction(const EdgeID via_edge,
- std::vector<ConnectedRoad> intersection) const
-{
- // BOOST_ASSERT(!intersection[0].entry_allowed); //This fails due to @themarex handling of dead
- // end
- // streets
- const auto &in_data = node_based_graph.GetEdgeData(via_edge);
-
- // coming from motorway
- if (detail::isMotorwayClass(in_data.road_classification.road_class))
- {
- return handleFromMotorway(via_edge, std::move(intersection));
- }
- else // coming from a ramp
- {
- return handleMotorwayRamp(via_edge, std::move(intersection));
- // ramp merging straight onto motorway
- }
-}
-
-bool TurnAnalysis::isMotorwayJunction(const EdgeID via_edge,
- const std::vector<ConnectedRoad> &intersection) const
-{
- bool has_motorway = false;
- bool has_normal_roads = false;
-
- for (const auto &road : intersection)
- {
- const auto &out_data = node_based_graph.GetEdgeData(road.turn.eid);
- // not merging or forking?
- if ((angularDeviation(road.turn.angle, 0) > 35 &&
- angularDeviation(road.turn.angle, 180) > 35) ||
- (road.entry_allowed && angularDeviation(road.turn.angle, 0) < 35))
- return false;
- else if (out_data.road_classification.road_class == FunctionalRoadClass::MOTORWAY ||
- out_data.road_classification.road_class == FunctionalRoadClass::TRUNK)
- {
- if (road.entry_allowed)
- has_motorway = true;
- }
- else if (!isRampClass(out_data.road_classification.road_class))
- has_normal_roads = true;
- }
-
- if (has_normal_roads)
- return false;
-
- const auto &in_data = node_based_graph.GetEdgeData(via_edge);
- return has_motorway ||
- in_data.road_classification.road_class == FunctionalRoadClass::MOTORWAY ||
- in_data.road_classification.road_class == FunctionalRoadClass::TRUNK;
-}
-
-TurnType TurnAnalysis::findBasicTurnType(const EdgeID via_edge, const ConnectedRoad &road) const
-{
-
- const auto &in_data = node_based_graph.GetEdgeData(via_edge);
- const auto &out_data = node_based_graph.GetEdgeData(road.turn.eid);
-
- bool on_ramp = isRampClass(in_data.road_classification.road_class);
-
- bool onto_ramp = isRampClass(out_data.road_classification.road_class);
-
- if (!on_ramp && onto_ramp)
- return TurnType::Ramp;
-
- if (in_data.name_id == out_data.name_id && in_data.name_id != INVALID_NAME_ID)
- {
- return TurnType::Continue;
- }
-
- return TurnType::Turn;
-}
-
-TurnInstruction TurnAnalysis::getInstructionForObvious(const std::size_t num_roads,
- const EdgeID via_edge,
- const ConnectedRoad &road) const
-{
- const auto type = findBasicTurnType(via_edge, road);
- // handle travel modes:
- const auto in_mode = node_based_graph.GetEdgeData(via_edge).travel_mode;
- const auto out_mode = node_based_graph.GetEdgeData(road.turn.eid).travel_mode;
- if (type == TurnType::Ramp)
- {
- return {TurnType::Ramp, getTurnDirection(road.turn.angle)};
- }
-
- if (angularDeviation(road.turn.angle, 0) < 0.01)
- {
- return {TurnType::Turn, DirectionModifier::UTurn};
- }
- if (type == TurnType::Turn)
- {
- const auto &in_data = node_based_graph.GetEdgeData(via_edge);
- const auto &out_data = node_based_graph.GetEdgeData(road.turn.eid);
- if (in_data.name_id != out_data.name_id &&
- requiresNameAnnounced(name_table.GetNameForID(in_data.name_id),
- name_table.GetNameForID(out_data.name_id)))
- return {TurnType::NewName, getTurnDirection(road.turn.angle)};
- else
- {
- if (in_mode == out_mode)
- return {TurnType::Suppressed, getTurnDirection(road.turn.angle)};
- else
- return {TurnType::Notification, getTurnDirection(road.turn.angle)};
- }
- }
- BOOST_ASSERT(type == TurnType::Continue);
- if (in_mode != out_mode)
- {
- return {TurnType::Notification, getTurnDirection(road.turn.angle)};
- }
- if (num_roads > 2)
- {
- return {TurnType::Suppressed, getTurnDirection(road.turn.angle)};
- }
- else
- {
- return {TurnType::NoTurn, getTurnDirection(road.turn.angle)};
- }
-}
-
-std::vector<ConnectedRoad>
-TurnAnalysis::handleOneWayTurn(std::vector<ConnectedRoad> intersection) const
-{
- BOOST_ASSERT(intersection[0].turn.angle < 0.001);
- return intersection;
-}
-
-std::vector<ConnectedRoad>
-TurnAnalysis::handleTwoWayTurn(const EdgeID via_edge, std::vector<ConnectedRoad> intersection) const
-{
- BOOST_ASSERT(intersection[0].turn.angle < 0.001);
- intersection[1].turn.instruction =
- getInstructionForObvious(intersection.size(), via_edge, intersection[1]);
-
- if (intersection[1].turn.instruction.type == TurnType::Suppressed)
- intersection[1].turn.instruction.type = TurnType::NoTurn;
-
- return intersection;
-}
-
-std::vector<ConnectedRoad>
-TurnAnalysis::handleThreeWayTurn(const EdgeID via_edge,
- std::vector<ConnectedRoad> intersection) const
-{
- BOOST_ASSERT(intersection[0].turn.angle < 0.001);
- const auto isObviousOfTwo = [](const ConnectedRoad road, const ConnectedRoad other)
- {
- return (angularDeviation(road.turn.angle, STRAIGHT_ANGLE) < NARROW_TURN_ANGLE &&
- angularDeviation(other.turn.angle, STRAIGHT_ANGLE) > 85) ||
- (angularDeviation(road.turn.angle, STRAIGHT_ANGLE) <
- std::numeric_limits<double>::epsilon()) ||
- (angularDeviation(other.turn.angle, STRAIGHT_ANGLE) /
- angularDeviation(road.turn.angle, STRAIGHT_ANGLE) >
- 1.4);
- };
-
- /* Two nearly straight turns -> FORK
- OOOOOOO
- /
- IIIIII
- \
- OOOOOOO
- */
- if (angularDeviation(intersection[1].turn.angle, STRAIGHT_ANGLE) < NARROW_TURN_ANGLE &&
- angularDeviation(intersection[2].turn.angle, STRAIGHT_ANGLE) < NARROW_TURN_ANGLE)
- {
- if (intersection[1].entry_allowed && intersection[2].entry_allowed)
- {
- const auto left_class = node_based_graph.GetEdgeData(intersection[2].turn.eid)
- .road_classification.road_class;
- const auto right_class = node_based_graph.GetEdgeData(intersection[1].turn.eid)
- .road_classification.road_class;
- if (canBeSeenAsFork(left_class, right_class))
- assignFork(via_edge, intersection[2], intersection[1]);
- else if (getPriority(left_class) > getPriority(right_class))
- {
- intersection[1].turn.instruction =
- getInstructionForObvious(intersection.size(), via_edge, intersection[1]);
- intersection[2].turn.instruction = {findBasicTurnType(via_edge, intersection[2]),
- DirectionModifier::SlightLeft};
- }
- else
- {
- intersection[2].turn.instruction =
- getInstructionForObvious(intersection.size(), via_edge, intersection[2]);
- intersection[1].turn.instruction = {findBasicTurnType(via_edge, intersection[1]),
- DirectionModifier::SlightRight};
- }
- }
- else
- {
- if (intersection[1].entry_allowed)
- intersection[1].turn.instruction =
- getInstructionForObvious(intersection.size(), via_edge, intersection[1]);
- if (intersection[2].entry_allowed)
- intersection[2].turn.instruction =
- getInstructionForObvious(intersection.size(), via_edge, intersection[2]);
- }
- }
- /* T Intersection
-
- OOOOOOO T OOOOOOOO
- I
- I
- I
- */
- else if (angularDeviation(intersection[1].turn.angle, 90) < NARROW_TURN_ANGLE &&
- angularDeviation(intersection[2].turn.angle, 270) < NARROW_TURN_ANGLE &&
- angularDeviation(intersection[1].turn.angle, intersection[2].turn.angle) >
- NARROW_TURN_ANGLE)
- {
- if (intersection[1].entry_allowed)
- {
- if (TurnType::Ramp != findBasicTurnType(via_edge, intersection[1]))
- intersection[1].turn.instruction = {TurnType::EndOfRoad, DirectionModifier::Right};
- else
- intersection[1].turn.instruction = {TurnType::Ramp, DirectionModifier::Right};
- }
- if (intersection[2].entry_allowed)
- {
- if (TurnType::Ramp != findBasicTurnType(via_edge, intersection[2]))
-
- intersection[2].turn.instruction = {TurnType::EndOfRoad, DirectionModifier::Left};
- else
- intersection[2].turn.instruction = {TurnType::Ramp, DirectionModifier::Left};
- }
- }
- /* T Intersection, Cross left
- O
- O
- O
- IIIIIIII - OOOOOOOOOO
- */
- else if (angularDeviation(intersection[1].turn.angle, STRAIGHT_ANGLE) < NARROW_TURN_ANGLE &&
- angularDeviation(intersection[2].turn.angle, 270) < NARROW_TURN_ANGLE &&
- angularDeviation(intersection[1].turn.angle, intersection[2].turn.angle) >
- NARROW_TURN_ANGLE)
- {
- if (intersection[1].entry_allowed)
- {
- if (TurnType::Ramp != findBasicTurnType(via_edge, intersection[1]))
- intersection[1].turn.instruction =
- getInstructionForObvious(intersection.size(), via_edge, intersection[1]);
- else
- intersection[1].turn.instruction = {TurnType::Ramp, DirectionModifier::Straight};
- }
- if (intersection[2].entry_allowed)
- {
- intersection[2].turn.instruction = {findBasicTurnType(via_edge, intersection[2]),
- DirectionModifier::Left};
- }
- }
- /* T Intersection, Cross right
-
- IIIIIIII T OOOOOOOOOO
- O
- O
- O
- */
- else if (angularDeviation(intersection[2].turn.angle, STRAIGHT_ANGLE) < NARROW_TURN_ANGLE &&
- angularDeviation(intersection[1].turn.angle, 90) < NARROW_TURN_ANGLE &&
- angularDeviation(intersection[1].turn.angle, intersection[2].turn.angle) >
- NARROW_TURN_ANGLE)
- {
- if (intersection[2].entry_allowed)
- intersection[2].turn.instruction =
- getInstructionForObvious(intersection.size(), via_edge, intersection[2]);
- if (intersection[1].entry_allowed)
- intersection[1].turn.instruction = {findBasicTurnType(via_edge, intersection[1]),
- DirectionModifier::Right};
- }
- // merge onto a through street
- else if (INVALID_NAME_ID != node_based_graph.GetEdgeData(intersection[1].turn.eid).name_id &&
- node_based_graph.GetEdgeData(intersection[1].turn.eid).name_id ==
- node_based_graph.GetEdgeData(intersection[2].turn.eid).name_id)
- {
- const auto findTurn = [isObviousOfTwo](const ConnectedRoad turn, const ConnectedRoad other)
- -> TurnInstruction
- {
- return {isObviousOfTwo(turn, other) ? TurnType::Merge : TurnType::Turn,
- getTurnDirection(turn.turn.angle)};
- };
- intersection[1].turn.instruction = findTurn(intersection[1], intersection[2]);
- intersection[2].turn.instruction = findTurn(intersection[2], intersection[1]);
- }
-
- // other street merges from the left
- else if (INVALID_NAME_ID != node_based_graph.GetEdgeData(via_edge).name_id &&
- node_based_graph.GetEdgeData(via_edge).name_id ==
- node_based_graph.GetEdgeData(intersection[1].turn.eid).name_id)
- {
- if (isObviousOfTwo(intersection[1], intersection[2]))
- {
- intersection[1].turn.instruction =
- TurnInstruction::SUPPRESSED(DirectionModifier::Straight);
- }
- else
- {
- intersection[1].turn.instruction = {TurnType::Continue,
- getTurnDirection(intersection[1].turn.angle)};
- }
- intersection[2].turn.instruction = {TurnType::Turn,
- getTurnDirection(intersection[2].turn.angle)};
- }
- // other street merges from the right
- else if (INVALID_NAME_ID != node_based_graph.GetEdgeData(via_edge).name_id &&
- node_based_graph.GetEdgeData(via_edge).name_id ==
- node_based_graph.GetEdgeData(intersection[2].turn.eid).name_id)
- {
- if (isObviousOfTwo(intersection[2], intersection[1]))
- {
- intersection[2].turn.instruction =
- TurnInstruction::SUPPRESSED(DirectionModifier::Straight);
- }
- else
- {
- intersection[2].turn.instruction = {TurnType::Continue,
- getTurnDirection(intersection[2].turn.angle)};
- }
- intersection[1].turn.instruction = {TurnType::Turn,
- getTurnDirection(intersection[1].turn.angle)};
- }
- else
- {
- if (isObviousOfTwo(intersection[1], intersection[2]))
- {
- intersection[1].turn.instruction = getInstructionForObvious(3,via_edge,intersection[1]);
- }
- else
- {
- intersection[1].turn.instruction = {TurnType::Turn,
- getTurnDirection(intersection[1].turn.angle)};
- }
-
- if (isObviousOfTwo(intersection[2], intersection[1]))
- {
- intersection[2].turn.instruction = getInstructionForObvious(3,via_edge,intersection[2]);
- }
- else
- {
- intersection[2].turn.instruction = {TurnType::Turn,
- getTurnDirection(intersection[2].turn.angle)};
- }
- }
- // unnamed intersections or basic three way turn
-
- // remain at basic turns
- // TODO handle obviousness, Handle Merges
- return intersection;
-}
+ const EdgeID onto_edge = road.turn.eid;
+ const NodeID to_nid = node_based_graph.GetTarget(onto_edge);
-void TurnAnalysis::handleDistinctConflict(const EdgeID via_edge,
- ConnectedRoad &left,
- ConnectedRoad &right) const
-{
- // single turn of both is valid (don't change the valid one)
- // or multiple identical angles -> bad OSM intersection
- if ((!left.entry_allowed || !right.entry_allowed) || (left.turn.angle == right.turn.angle))
- {
- if (left.entry_allowed)
- left.turn.instruction = {findBasicTurnType(via_edge, left),
- getTurnDirection(left.turn.angle)};
- if (right.entry_allowed)
- right.turn.instruction = {findBasicTurnType(via_edge, right),
- getTurnDirection(right.turn.angle)};
- return;
- }
-
- if (getTurnDirection(left.turn.angle) == DirectionModifier::Straight ||
- getTurnDirection(left.turn.angle) == DirectionModifier::SlightLeft ||
- getTurnDirection(right.turn.angle) == DirectionModifier::SlightRight)
- {
- const auto left_class =
- node_based_graph.GetEdgeData(left.turn.eid).road_classification.road_class;
- const auto right_class =
- node_based_graph.GetEdgeData(right.turn.eid).road_classification.road_class;
- if (canBeSeenAsFork(left_class, right_class))
- assignFork(via_edge, left, right);
- else if (getPriority(left_class) > getPriority(right_class))
- {
- // FIXME this should possibly know about the actual roads?
- right.turn.instruction = getInstructionForObvious(4, via_edge, right);
- left.turn.instruction = {findBasicTurnType(via_edge, left),
- DirectionModifier::SlightLeft};
- }
- else
- {
- // FIXME this should possibly know about the actual roads?
- left.turn.instruction = getInstructionForObvious(4, via_edge, left);
- right.turn.instruction = {findBasicTurnType(via_edge, right),
- DirectionModifier::SlightRight};
- }
- }
-
- const auto left_type = findBasicTurnType(via_edge, left);
- const auto right_type = findBasicTurnType(via_edge, right);
- // Two Right Turns
- if (angularDeviation(left.turn.angle, 90) < MAXIMAL_ALLOWED_NO_TURN_DEVIATION)
- {
- // Keep left perfect, shift right
- left.turn.instruction = {left_type, DirectionModifier::Right};
- right.turn.instruction = {right_type, DirectionModifier::SharpRight};
- return;
- }
- if (angularDeviation(right.turn.angle, 90) < MAXIMAL_ALLOWED_NO_TURN_DEVIATION)
- {
- // Keep Right perfect, shift left
- left.turn.instruction = {left_type, DirectionModifier::SlightRight};
- right.turn.instruction = {right_type, DirectionModifier::Right};
- return;
- }
- // Two Right Turns
- if (angularDeviation(left.turn.angle, 270) < MAXIMAL_ALLOWED_NO_TURN_DEVIATION)
- {
- // Keep left perfect, shift right
- left.turn.instruction = {left_type, DirectionModifier::Left};
- right.turn.instruction = {right_type, DirectionModifier::SlightLeft};
- return;
- }
- if (angularDeviation(right.turn.angle, 270) < MAXIMAL_ALLOWED_NO_TURN_DEVIATION)
- {
- // Keep Right perfect, shift left
- left.turn.instruction = {left_type, DirectionModifier::SharpLeft};
- right.turn.instruction = {right_type, DirectionModifier::Left};
- return;
- }
- // Both turns?
- if (TurnType::Ramp != left_type && TurnType::Ramp != right_type)
- {
- if (left.turn.angle < STRAIGHT_ANGLE)
- {
- left.turn.instruction = {TurnType::FirstTurn, getTurnDirection(left.turn.angle)};
- right.turn.instruction = {TurnType::SecondTurn, getTurnDirection(right.turn.angle)};
- }
- else
- {
- left.turn.instruction = {TurnType::SecondTurn, getTurnDirection(left.turn.angle)};
- right.turn.instruction = {TurnType::FirstTurn, getTurnDirection(right.turn.angle)};
- }
- return;
- }
- // Shift the lesser penalty
- if (getTurnDirection(left.turn.angle) == DirectionModifier::SharpLeft)
- {
- left.turn.instruction = {left_type, DirectionModifier::SharpLeft};
- right.turn.instruction = {right_type, DirectionModifier::Left};
- return;
- }
- if (getTurnDirection(right.turn.angle) == DirectionModifier::SharpRight)
- {
- left.turn.instruction = {left_type, DirectionModifier::Right};
- right.turn.instruction = {right_type, DirectionModifier::SharpRight};
- return;
- }
-
- if (getTurnDirection(left.turn.angle) == DirectionModifier::Right)
- {
- if (angularDeviation(left.turn.angle, 90) > angularDeviation(right.turn.angle, 90))
- {
- left.turn.instruction = {left_type, DirectionModifier::SlightRight};
- right.turn.instruction = {right_type, DirectionModifier::Right};
- }
- else
- {
- left.turn.instruction = {left_type, DirectionModifier::Right};
- right.turn.instruction = {right_type, DirectionModifier::SharpRight};
- }
- }
- else
- {
- if (angularDeviation(left.turn.angle, 270) > angularDeviation(right.turn.angle, 270))
- {
- left.turn.instruction = {left_type, DirectionModifier::SharpLeft};
- right.turn.instruction = {right_type, DirectionModifier::Left};
- }
- else
- {
- left.turn.instruction = {left_type, DirectionModifier::Left};
- right.turn.instruction = {right_type, DirectionModifier::SlightLeft};
- }
- }
-}
-
-std::vector<ConnectedRoad>
-TurnAnalysis::handleComplexTurn(const EdgeID via_edge,
- std::vector<ConnectedRoad> intersection) const
-{
- static int fallback_count = 0;
- const std::size_t obvious_index = findObviousTurn(via_edge, intersection);
- const auto fork_range = findFork(intersection);
- std::size_t straightmost_turn = 0;
- double straightmost_deviation = 180;
- for (std::size_t i = 0; i < intersection.size(); ++i)
- {
- const double deviation = angularDeviation(intersection[i].turn.angle, STRAIGHT_ANGLE);
- if (deviation < straightmost_deviation)
- {
- straightmost_deviation = deviation;
- straightmost_turn = i;
- }
- }
-
- if (obvious_index != 0)
- {
- intersection[obvious_index].turn.instruction =
- getInstructionForObvious(intersection.size(), via_edge, intersection[obvious_index]);
-
- // assign left/right turns
- intersection = assignLeftTurns(via_edge, std::move(intersection), obvious_index + 1);
- intersection = assignRightTurns(via_edge, std::move(intersection), obvious_index);
- }
- else if (fork_range.first != 0 && fork_range.second - fork_range.first <= 2) // found fork
- {
- if (fork_range.second - fork_range.first == 1)
- {
- auto &left = intersection[fork_range.second];
- auto &right = intersection[fork_range.first];
- const auto left_class =
- node_based_graph.GetEdgeData(left.turn.eid).road_classification.road_class;
- const auto right_class =
- node_based_graph.GetEdgeData(right.turn.eid).road_classification.road_class;
- if (canBeSeenAsFork(left_class, right_class))
- assignFork(via_edge, left, right);
- else if (getPriority(left_class) > getPriority(right_class))
- {
- right.turn.instruction =
- getInstructionForObvious(intersection.size(), via_edge, right);
- left.turn.instruction = {findBasicTurnType(via_edge, left),
- DirectionModifier::SlightLeft};
- }
- else
- {
- left.turn.instruction =
- getInstructionForObvious(intersection.size(), via_edge, left);
- right.turn.instruction = {findBasicTurnType(via_edge, right),
- DirectionModifier::SlightRight};
- }
- }
- else if (fork_range.second - fork_range.second == 2)
- {
- assignFork(via_edge, intersection[fork_range.second],
- intersection[fork_range.first + 1], intersection[fork_range.first]);
- }
- // assign left/right turns
- intersection = assignLeftTurns(via_edge, std::move(intersection), fork_range.second + 1);
- intersection = assignRightTurns(via_edge, std::move(intersection), fork_range.first);
- }
- else if (straightmost_deviation < FUZZY_ANGLE_DIFFERENCE &&
- !intersection[straightmost_turn].entry_allowed)
- {
- // invalid straight turn
- intersection = assignLeftTurns(via_edge, std::move(intersection), straightmost_turn + 1);
- intersection = assignRightTurns(via_edge, std::move(intersection), straightmost_turn);
- }
- // no straight turn
- else if (intersection[straightmost_turn].turn.angle > 180)
- {
- // at most three turns on either side
- intersection = assignLeftTurns(via_edge, std::move(intersection), straightmost_turn);
- intersection = assignRightTurns(via_edge, std::move(intersection), straightmost_turn);
- }
- else if (intersection[straightmost_turn].turn.angle < 180)
- {
- intersection = assignLeftTurns(via_edge, std::move(intersection), straightmost_turn + 1);
- intersection = assignRightTurns(via_edge, std::move(intersection), straightmost_turn + 1);
- }
- else
- {
- if (fallback_count++ < 10)
- {
- const auto coord = localizer(node_based_graph.GetTarget(via_edge));
- util::SimpleLogger().Write(logWARNING)
- << "Resolved to keep fallback on complex turn assignment at "
- << std::setprecision(12) << toFloating(coord.lat) << " " << toFloating(coord.lon)
- << "Straightmost: " << straightmost_turn;
- ;
- for (const auto &road : intersection)
- {
- const auto &out_data = node_based_graph.GetEdgeData(road.turn.eid);
- util::SimpleLogger().Write(logWARNING)
- << "road: " << road.toString() << " Name: " << out_data.name_id
- << " Road Class: " << (int)out_data.road_classification.road_class
- << " At: " << localizer(node_based_graph.GetTarget(road.turn.eid));
- }
- }
- }
- return intersection;
-}
-
-// Sets basic turn types as fallback for otherwise unhandled turns
-std::vector<ConnectedRoad> TurnAnalysis::setTurnTypes(const NodeID from,
- const EdgeID via_edge,
- std::vector<ConnectedRoad> intersection) const
-{
- for (auto &road : intersection)
- {
- if (!road.entry_allowed)
- continue;
-
- const EdgeID onto_edge = road.turn.eid;
- const NodeID to_node = node_based_graph.GetTarget(onto_edge);
-
- road.turn.instruction = (from == to_node)
- ? TurnInstruction{TurnType::Turn, DirectionModifier::UTurn}
- : TurnInstruction{findBasicTurnType(via_edge, road),
- getTurnDirection(road.turn.angle)};
- }
- return intersection;
-}
-
-// a
-// |
-// |
-// v
-// For an intersection from_node --via_edi--> turn_node ----> c
-// ^
-// |
-// |
-// b
-// This functions returns _all_ turns as if the graph was undirected.
-// That means we not only get (from_node, turn_node, c) in the above example
-// but also (from_node, turn_node, a), (from_node, turn_node, b). These turns are
-// marked as invalid and only needed for intersection classification.
-std::vector<ConnectedRoad> TurnAnalysis::getConnectedRoads(const NodeID from_node,
- const EdgeID via_eid) const
-{
- std::vector<ConnectedRoad> intersection;
- const NodeID turn_node = node_based_graph.GetTarget(via_eid);
- const NodeID only_restriction_to_node =
- restriction_map.CheckForEmanatingIsOnlyTurn(from_node, turn_node);
- const bool is_barrier_node = barrier_nodes.find(turn_node) != barrier_nodes.end();
-
- bool has_uturn_edge = false;
- for (const EdgeID onto_edge : node_based_graph.GetAdjacentEdgeRange(turn_node))
- {
- BOOST_ASSERT(onto_edge != SPECIAL_EDGEID);
- const NodeID to_node = node_based_graph.GetTarget(onto_edge);
-
- bool turn_is_valid =
- // reverse edges are never valid turns because the resulting turn would look like this:
- // from_node --via_edge--> turn_node <--onto_edge-- to_node
- // however we need this for capture intersection shape for incoming one-ways
- !node_based_graph.GetEdgeData(onto_edge).reversed &&
- // we are not turning over a barrier
- (!is_barrier_node || from_node == to_node) &&
- // We are at an only_-restriction but not at the right turn.
- (only_restriction_to_node == SPECIAL_NODEID || to_node == only_restriction_to_node) &&
- // the turn is not restricted
- !restriction_map.CheckIfTurnIsRestricted(from_node, turn_node, to_node);
-
- auto angle = 0.;
- if (from_node == to_node)
- {
- if (turn_is_valid && !is_barrier_node)
- {
- // we only add u-turns for dead-end streets.
- if (node_based_graph.GetOutDegree(turn_node) > 1)
- {
- auto number_of_emmiting_bidirectional_edges = 0;
- for (auto edge : node_based_graph.GetAdjacentEdgeRange(turn_node))
- {
- auto target = node_based_graph.GetTarget(edge);
- auto reverse_edge = node_based_graph.FindEdge(target, turn_node);
- BOOST_ASSERT(reverse_edge != SPECIAL_EDGEID);
- if (!node_based_graph.GetEdgeData(reverse_edge).reversed)
- {
- ++number_of_emmiting_bidirectional_edges;
- }
- }
- // is a dead-end
- turn_is_valid = number_of_emmiting_bidirectional_edges <= 1;
- }
- }
- has_uturn_edge = true;
- BOOST_ASSERT(angle >= 0. && angle < std::numeric_limits<double>::epsilon());
- }
- else
- {
- // unpack first node of second segment if packed
- const auto first_coordinate = getRepresentativeCoordinate(
- from_node, turn_node, via_eid, INVERT, compressed_edge_container, node_info_list);
- const auto third_coordinate = getRepresentativeCoordinate(
- turn_node, to_node, onto_edge, !INVERT, compressed_edge_container, node_info_list);
- angle = util::coordinate_calculation::computeAngle(
- first_coordinate, node_info_list[turn_node], third_coordinate);
- if (angle < std::numeric_limits<double>::epsilon())
- has_uturn_edge = true;
- }
-
- intersection.push_back(ConnectedRoad(
- TurnOperation{onto_edge, angle, {TurnType::Invalid, DirectionModifier::UTurn}},
- turn_is_valid));
- }
-
- // We hit the case of a street leading into nothing-ness. Since the code here assumes that this
- // will
- // never happen we add an artificial invalid uturn in this case.
- if (!has_uturn_edge)
- {
- intersection.push_back(
- {TurnOperation{via_eid, 0., {TurnType::Invalid, DirectionModifier::UTurn}}, false});
- }
-
- const auto ByAngle = [](const ConnectedRoad &first, const ConnectedRoad second)
- {
- return first.turn.angle < second.turn.angle;
- };
- std::sort(std::begin(intersection), std::end(intersection), ByAngle);
-
- BOOST_ASSERT(intersection[0].turn.angle >= 0. &&
- intersection[0].turn.angle < std::numeric_limits<double>::epsilon());
-
- return mergeSegregatedRoads(std::move(intersection));
-}
-
-/*
- * Segregated Roads often merge onto a single intersection.
- * While technically representing different roads, they are
- * often looked at as a single road.
- * Due to the merging, turn Angles seem off, wenn we compute them from the
- * initial positions.
- *
- * b<b<b<b(1)<b<b<b
- * aaaaa-b
- * b>b>b>b(2)>b>b>b
- *
- * Would be seen as a slight turn going fro a to (2). A Sharp turn going from
- * (1) to (2).
- *
- * In cases like these, we megre this segregated roads into a single road to
- * end up with a case like:
- *
- * aaaaa-bbbbbb
- *
- * for the turn representation.
- * Anything containing the first u-turn in a merge affects all other angles
- * and is handled separately from all others.
- */
-std::vector<ConnectedRoad>
-TurnAnalysis::mergeSegregatedRoads(std::vector<ConnectedRoad> intersection) const
-{
- const auto getRight = [&](std::size_t index)
- {
- return (index + intersection.size() - 1) % intersection.size();
- };
-
- const auto mergable = [&](std::size_t first, std::size_t second) -> bool
- {
- const auto &first_data = node_based_graph.GetEdgeData(intersection[first].turn.eid);
- const auto &second_data = node_based_graph.GetEdgeData(intersection[second].turn.eid);
-
- return first_data.name_id != INVALID_NAME_ID && first_data.name_id == second_data.name_id &&
- !first_data.roundabout && !second_data.roundabout &&
- first_data.travel_mode == second_data.travel_mode &&
- first_data.road_classification == second_data.road_classification &&
- // compatible threshold
- angularDeviation(intersection[first].turn.angle, intersection[second].turn.angle) <
- 60 &&
- first_data.reversed != second_data.reversed;
- };
-
- const auto merge = [](const ConnectedRoad &first, const ConnectedRoad &second) -> ConnectedRoad
- {
- if (!first.entry_allowed)
- {
- ConnectedRoad result = second;
- result.turn.angle = (first.turn.angle + second.turn.angle) / 2;
- if (first.turn.angle - second.turn.angle > 180)
- result.turn.angle += 180;
- if (result.turn.angle > 360)
- result.turn.angle -= 360;
-
- return result;
- }
- else
- {
- BOOST_ASSERT(!second.entry_allowed);
- ConnectedRoad result = first;
- result.turn.angle = (first.turn.angle + second.turn.angle) / 2;
-
- if (first.turn.angle - second.turn.angle > 180)
- result.turn.angle += 180;
- if (result.turn.angle > 360)
- result.turn.angle -= 360;
-
- return result;
- }
- };
- if (intersection.size() == 1)
- return intersection;
-
- // check for merges including the basic u-turn
- // these result in an adjustment of all other angles
- if (mergable(0, intersection.size() - 1))
- {
- // std::cout << "First merge" << std::endl;
- const double correction_factor =
- (360 - intersection[intersection.size() - 1].turn.angle) / 2;
- for (std::size_t i = 1; i + 1 < intersection.size(); ++i)
- intersection[i].turn.angle += correction_factor;
- intersection[0] = merge(intersection.front(), intersection.back());
- intersection[0].turn.angle = 0;
- intersection.pop_back();
- }
- else if (mergable(0, 1))
- {
- // std::cout << "First merge" << std::endl;
- const double correction_factor = (intersection[1].turn.angle) / 2;
- for (std::size_t i = 2; i < intersection.size(); ++i)
- intersection[i].turn.angle += correction_factor;
- intersection[0] = merge(intersection[0], intersection[1]);
- intersection[0].turn.angle = 0;
- intersection.erase(intersection.begin() + 1);
- }
-
- // a merge including the first u-turn requres an adjustment of the turn angles
- // therefore these are handled prior to this step
- for (std::size_t index = 2; index < intersection.size(); ++index)
- {
- if (mergable(index, getRight(index)))
- {
- intersection[getRight(index)] =
- merge(intersection[getRight(index)], intersection[index]);
- intersection.erase(intersection.begin() + index);
- --index;
- }
- }
-
- const auto ByAngle = [](const ConnectedRoad &first, const ConnectedRoad second)
- {
- return first.turn.angle < second.turn.angle;
- };
- std::sort(std::begin(intersection), std::end(intersection), ByAngle);
- return intersection;
-}
-
-void TurnAnalysis::assignFork(const EdgeID via_edge,
- ConnectedRoad &left,
- ConnectedRoad &right) const
-{
- const auto &in_data = node_based_graph.GetEdgeData(via_edge);
- const bool low_priority_left = isLowPriorityRoadClass(
- node_based_graph.GetEdgeData(left.turn.eid).road_classification.road_class);
- const bool low_priority_right = isLowPriorityRoadClass(
- node_based_graph.GetEdgeData(right.turn.eid).road_classification.road_class);
- if ((angularDeviation(left.turn.angle, STRAIGHT_ANGLE) < MAXIMAL_ALLOWED_NO_TURN_DEVIATION &&
- angularDeviation(right.turn.angle, STRAIGHT_ANGLE) > FUZZY_ANGLE_DIFFERENCE))
- {
- // left side is actually straight
- const auto &out_data = node_based_graph.GetEdgeData(left.turn.eid);
- if (requiresAnnouncement(in_data, out_data))
- {
- if (low_priority_right && !low_priority_left)
- {
- left.turn.instruction = getInstructionForObvious(3, via_edge, left);
- right.turn.instruction = {findBasicTurnType(via_edge, right),
- DirectionModifier::SlightRight};
- }
- else
- {
- if (low_priority_left && !low_priority_right)
- {
- left.turn.instruction = {findBasicTurnType(via_edge, left),
- DirectionModifier::SlightLeft};
- right.turn.instruction = {findBasicTurnType(via_edge, right),
- DirectionModifier::SlightRight};
- }
- else
- {
- left.turn.instruction = {TurnType::Fork, DirectionModifier::SlightLeft};
- right.turn.instruction = {TurnType::Fork, DirectionModifier::SlightRight};
- }
- }
- }
- else
- {
- left.turn.instruction = {TurnType::Suppressed, DirectionModifier::Straight};
- right.turn.instruction = {findBasicTurnType(via_edge, right),
- DirectionModifier::SlightRight};
- }
- }
- else if (angularDeviation(right.turn.angle, STRAIGHT_ANGLE) <
- MAXIMAL_ALLOWED_NO_TURN_DEVIATION &&
- angularDeviation(left.turn.angle, STRAIGHT_ANGLE) > FUZZY_ANGLE_DIFFERENCE)
- {
- // right side is actually straight
- const auto &out_data = node_based_graph.GetEdgeData(right.turn.eid);
- if (angularDeviation(right.turn.angle, STRAIGHT_ANGLE) <
- MAXIMAL_ALLOWED_NO_TURN_DEVIATION &&
- angularDeviation(left.turn.angle, STRAIGHT_ANGLE) > FUZZY_ANGLE_DIFFERENCE)
- {
- if (requiresAnnouncement(in_data, out_data))
- {
- if (low_priority_left && !low_priority_right)
- {
- left.turn.instruction = {findBasicTurnType(via_edge, left),
- DirectionModifier::SlightLeft};
- right.turn.instruction = getInstructionForObvious(3, via_edge, right);
- }
- else
- {
- if (low_priority_right && !low_priority_left)
- {
- left.turn.instruction = {findBasicTurnType(via_edge, left),
- DirectionModifier::SlightLeft};
- right.turn.instruction = {findBasicTurnType(via_edge, right),
- DirectionModifier::SlightRight};
- }
- else
- {
- right.turn.instruction = {TurnType::Fork, DirectionModifier::SlightRight};
- left.turn.instruction = {TurnType::Fork, DirectionModifier::SlightLeft};
- }
- }
- }
- else
- {
- right.turn.instruction = {TurnType::Suppressed, DirectionModifier::Straight};
- left.turn.instruction = {findBasicTurnType(via_edge, left),
- DirectionModifier::SlightLeft};
- }
- }
- }
- else
- {
- // left side of fork
- if (low_priority_right && !low_priority_left)
- left.turn.instruction = {TurnType::Suppressed, DirectionModifier::SlightLeft};
- else
- {
- if (low_priority_left && !low_priority_right)
- left.turn.instruction = {TurnType::Turn, DirectionModifier::SlightLeft};
- else
- left.turn.instruction = {TurnType::Fork, DirectionModifier::SlightLeft};
- }
-
- // right side of fork
- if (low_priority_left && !low_priority_right)
- right.turn.instruction = {TurnType::Suppressed, DirectionModifier::SlightLeft};
- else
- {
- if (low_priority_right && !low_priority_left)
- right.turn.instruction = {TurnType::Turn, DirectionModifier::SlightRight};
- else
- right.turn.instruction = {TurnType::Fork, DirectionModifier::SlightRight};
- }
- }
-}
-
-void TurnAnalysis::assignFork(const EdgeID via_edge,
- ConnectedRoad &left,
- ConnectedRoad ¢er,
- ConnectedRoad &right) const
-{
- // TODO handle low priority road classes in a reasonable way
- if (left.entry_allowed && center.entry_allowed && right.entry_allowed)
- {
- left.turn.instruction = {TurnType::Fork, DirectionModifier::SlightLeft};
- if (angularDeviation(center.turn.angle, 180) < MAXIMAL_ALLOWED_NO_TURN_DEVIATION)
- {
- const auto &in_data = node_based_graph.GetEdgeData(via_edge);
- const auto &out_data = node_based_graph.GetEdgeData(center.turn.eid);
- if (requiresAnnouncement(in_data, out_data))
- {
- center.turn.instruction = {TurnType::Fork, DirectionModifier::Straight};
- }
- else
- {
- center.turn.instruction = {TurnType::Suppressed, DirectionModifier::Straight};
- }
- }
- else
- {
- center.turn.instruction = {TurnType::Fork, DirectionModifier::Straight};
- }
- right.turn.instruction = {TurnType::Fork, DirectionModifier::SlightRight};
- }
- else if (left.entry_allowed)
- {
- if (right.entry_allowed)
- assignFork(via_edge, left, right);
- else if (center.entry_allowed)
- assignFork(via_edge, left, center);
- else
- left.turn.instruction = {findBasicTurnType(via_edge, left),
- getTurnDirection(left.turn.angle)};
- }
- else if (right.entry_allowed)
- {
- if (center.entry_allowed)
- assignFork(via_edge, center, right);
- else
- right.turn.instruction = {findBasicTurnType(via_edge, right),
- getTurnDirection(right.turn.angle)};
- }
- else
- {
- if (center.entry_allowed)
- center.turn.instruction = {findBasicTurnType(via_edge, center),
- getTurnDirection(center.turn.angle)};
- }
-}
-
-std::size_t TurnAnalysis::findObviousTurn(const EdgeID via_edge,
- const std::vector<ConnectedRoad> &intersection) const
-{
- // no obvious road
- if (intersection.size() == 1)
- return 0;
-
- // a single non u-turn is obvious
- if (intersection.size() == 2)
- return 1;
-
- // at least three roads
- std::size_t best = 0;
- double best_deviation = 180;
-
- std::size_t best_continue = 0;
- double best_continue_deviation = 180;
-
- const EdgeData &in_data = node_based_graph.GetEdgeData(via_edge);
- for (std::size_t i = 1; i < intersection.size(); ++i)
- {
- const double deviation = angularDeviation(intersection[i].turn.angle, STRAIGHT_ANGLE);
- if (intersection[i].entry_allowed && deviation < best_deviation)
- {
- best_deviation = deviation;
- best = i;
- }
-
- const auto out_data = node_based_graph.GetEdgeData(intersection[i].turn.eid);
- if (intersection[i].entry_allowed && out_data.name_id == in_data.name_id &&
- deviation < best_continue_deviation)
- {
- best_continue_deviation = deviation;
- best_continue = i;
- }
- }
-
- if (best == 0)
- return 0;
-
- if (best_deviation >= 2 * NARROW_TURN_ANGLE)
- return 0;
-
- // TODO incorporate road class in decision
- if (best != 0 && best_deviation < MAXIMAL_ALLOWED_NO_TURN_DEVIATION)
- {
- return best;
- }
-
- // has no obvious continued road
- if (best_continue == 0 || true)
- {
- // Find left/right deviation
- const double left_deviation = angularDeviation(
- intersection[(best + 1) % intersection.size()].turn.angle, STRAIGHT_ANGLE);
- const double right_deviation =
- angularDeviation(intersection[best - 1].turn.angle, STRAIGHT_ANGLE);
-
- if (best_deviation < MAXIMAL_ALLOWED_NO_TURN_DEVIATION &&
- std::min(left_deviation, right_deviation) > FUZZY_ANGLE_DIFFERENCE)
- return best;
-
- // other narrow turns?
- if (angularDeviation(intersection[best - 1].turn.angle, STRAIGHT_ANGLE) <=
- FUZZY_ANGLE_DIFFERENCE)
- return 0;
- if (angularDeviation(intersection[(best + 1) % intersection.size()].turn.angle,
- STRAIGHT_ANGLE) <= FUZZY_ANGLE_DIFFERENCE)
- return 0;
-
- // Well distinct turn that is nearly straight
- if (left_deviation / best_deviation >= DISTINCTION_RATIO &&
- right_deviation / best_deviation >= DISTINCTION_RATIO)
- {
- return best;
- }
- }
-
- return 0; // no obvious turn
-}
-
-std::pair<std::size_t, std::size_t>
-TurnAnalysis::findFork(const std::vector<ConnectedRoad> &intersection) const
-{
-
- std::size_t best = 0;
- double best_deviation = 180;
-
- // TODO handle road classes
- for (std::size_t i = 1; i < intersection.size(); ++i)
- {
- const double deviation = angularDeviation(intersection[i].turn.angle, STRAIGHT_ANGLE);
- if (intersection[i].entry_allowed && deviation < best_deviation)
- {
- best_deviation = deviation;
- best = i;
- }
- }
-
- if (best_deviation <= NARROW_TURN_ANGLE)
- {
- std::size_t left = best, right = best;
- while (left + 1 < intersection.size() &&
- angularDeviation(intersection[left].turn.angle, intersection[left + 1].turn.angle) <
- NARROW_TURN_ANGLE)
- ++left;
- while (right > 1 &&
- angularDeviation(intersection[right].turn.angle,
- intersection[right - 1].turn.angle) < NARROW_TURN_ANGLE)
- --right;
-
- // TODO check whether 2*NARROW_TURN is too large
- if (right < left &&
- angularDeviation(intersection[left].turn.angle,
- intersection[(left + 1) % intersection.size()].turn.angle) >=
- 2 * NARROW_TURN_ANGLE &&
- angularDeviation(intersection[right].turn.angle, intersection[right - 1].turn.angle) >=
- 2 * NARROW_TURN_ANGLE)
- return std::make_pair(right, left);
- }
- return std::make_pair(0llu, 0llu);
-}
-
-// Can only assign three turns
-std::vector<ConnectedRoad> TurnAnalysis::assignLeftTurns(const EdgeID via_edge,
- std::vector<ConnectedRoad> intersection,
- const std::size_t starting_at) const
-{
- const auto count_valid = [&intersection, starting_at]()
- {
- std::size_t count = 0;
- for (std::size_t i = starting_at; i < intersection.size(); ++i)
- if (intersection[i].entry_allowed)
- ++count;
- return count;
- };
- if (starting_at == intersection.size() || count_valid() == 0)
- return intersection;
- // handle single turn
- if (intersection.size() - starting_at == 1)
- {
- if (!intersection[starting_at].entry_allowed)
- return intersection;
-
- if (angularDeviation(intersection[starting_at].turn.angle, STRAIGHT_ANGLE) >
- NARROW_TURN_ANGLE &&
- angularDeviation(intersection[starting_at].turn.angle, 0) > NARROW_TURN_ANGLE)
- {
- // assign left turn
- intersection[starting_at].turn.instruction = {
- findBasicTurnType(via_edge, intersection[starting_at]), DirectionModifier::Left};
- }
- else if (angularDeviation(intersection[starting_at].turn.angle, STRAIGHT_ANGLE) <=
- NARROW_TURN_ANGLE)
- {
- intersection[starting_at].turn.instruction = {
- findBasicTurnType(via_edge, intersection[starting_at]),
- DirectionModifier::SlightLeft};
- }
- else
- {
- intersection[starting_at].turn.instruction = {
- findBasicTurnType(via_edge, intersection[starting_at]),
- DirectionModifier::SharpLeft};
- }
- }
- // two turns on at the side
- else if (intersection.size() - starting_at == 2)
- {
- const auto first_direction = getTurnDirection(intersection[starting_at].turn.angle);
- const auto second_direction = getTurnDirection(intersection[starting_at + 1].turn.angle);
- if (first_direction == second_direction)
- {
- // conflict
- handleDistinctConflict(via_edge, intersection[starting_at + 1],
- intersection[starting_at]);
- }
- else
- {
- intersection[starting_at].turn.instruction = {
- findBasicTurnType(via_edge, intersection[starting_at]), first_direction};
- intersection[starting_at + 1].turn.instruction = {
- findBasicTurnType(via_edge, intersection[starting_at + 1]), second_direction};
- }
- }
- else if (intersection.size() - starting_at == 3)
- {
- const auto first_direction = getTurnDirection(intersection[starting_at].turn.angle);
- const auto second_direction = getTurnDirection(intersection[starting_at + 1].turn.angle);
- const auto third_direction = getTurnDirection(intersection[starting_at + 2].turn.angle);
- if (first_direction != second_direction && second_direction != third_direction)
- {
- // implies first != third, based on the angles and clockwise order
- if (intersection[starting_at].entry_allowed)
- intersection[starting_at].turn.instruction = {
- findBasicTurnType(via_edge, intersection[starting_at]), first_direction};
- if (intersection[starting_at + 1].entry_allowed)
- intersection[starting_at + 1].turn.instruction = {
- findBasicTurnType(via_edge, intersection[starting_at + 1]), second_direction};
- if (intersection[starting_at + 2].entry_allowed)
- intersection[starting_at + 2].turn.instruction = {
- findBasicTurnType(via_edge, intersection[starting_at + 2]), second_direction};
- }
- else if (2 >= (intersection[starting_at].entry_allowed +
- intersection[starting_at + 1].entry_allowed +
- intersection[starting_at + 2].entry_allowed))
- {
- // at least one invalid turn
- if (!intersection[starting_at].entry_allowed)
- {
- handleDistinctConflict(via_edge, intersection[starting_at + 2],
- intersection[starting_at + 1]);
- }
- else if (!intersection[starting_at + 1].entry_allowed)
- {
- handleDistinctConflict(via_edge, intersection[starting_at + 2],
- intersection[starting_at]);
- }
- else
- {
- handleDistinctConflict(via_edge, intersection[starting_at + 1],
- intersection[starting_at]);
- }
- }
- else if (intersection[starting_at].entry_allowed &&
- intersection[starting_at + 1].entry_allowed &&
- intersection[starting_at + 2].entry_allowed &&
- angularDeviation(intersection[starting_at].turn.angle,
- intersection[starting_at + 1].turn.angle) >= NARROW_TURN_ANGLE &&
- angularDeviation(intersection[starting_at + 1].turn.angle,
- intersection[starting_at + 2].turn.angle) >= NARROW_TURN_ANGLE)
- {
- intersection[starting_at].turn.instruction = {
- findBasicTurnType(via_edge, intersection[starting_at]),
- DirectionModifier::SlightLeft};
- intersection[starting_at + 1].turn.instruction = {
- findBasicTurnType(via_edge, intersection[starting_at + 1]),
- DirectionModifier::Left};
- intersection[starting_at + 2].turn.instruction = {
- findBasicTurnType(via_edge, intersection[starting_at + 2]),
- DirectionModifier::SharpLeft};
- }
- else if (intersection[starting_at].entry_allowed &&
- intersection[starting_at + 1].entry_allowed &&
- intersection[starting_at + 2].entry_allowed &&
- ((first_direction == second_direction && second_direction == third_direction) ||
- (third_direction == second_direction &&
- angularDeviation(intersection[starting_at].turn.angle,
- intersection[starting_at + 1].turn.angle) < GROUP_ANGLE) ||
- (second_direction == first_direction &&
- angularDeviation(intersection[starting_at + 1].turn.angle,
- intersection[starting_at + 2].turn.angle) < GROUP_ANGLE)))
- {
- intersection[starting_at].turn.instruction = {
- detail::isRampClass(intersection[starting_at].turn.eid, node_based_graph)
- ? FirstRamp
- : FirstTurn,
- second_direction};
- intersection[starting_at + 1].turn.instruction = {
- detail::isRampClass(intersection[starting_at + 1].turn.eid, node_based_graph)
- ? SecondRamp
- : SecondTurn,
- second_direction};
- intersection[starting_at + 2].turn.instruction = {
- detail::isRampClass(intersection[starting_at + 2].turn.eid, node_based_graph)
- ? ThirdRamp
- : ThirdTurn,
- second_direction};
- }
- else if (intersection[starting_at].entry_allowed &&
- intersection[starting_at + 1].entry_allowed &&
- intersection[starting_at + 2].entry_allowed &&
- ((third_direction == second_direction &&
- angularDeviation(intersection[starting_at].turn.angle,
- intersection[starting_at + 1].turn.angle) >= GROUP_ANGLE) ||
- (second_direction == first_direction &&
- angularDeviation(intersection[starting_at + 1].turn.angle,
- intersection[starting_at + 2].turn.angle) >= GROUP_ANGLE)))
- {
- // conflict one side with an additional very sharp turn
- if (angularDeviation(intersection[starting_at + 1].turn.angle,
- intersection[starting_at + 2].turn.angle) >= GROUP_ANGLE)
- {
- handleDistinctConflict(via_edge, intersection[starting_at + 1],
- intersection[starting_at]);
- intersection[starting_at + 2].turn.instruction = {
- findBasicTurnType(via_edge, intersection[starting_at + 2]), third_direction};
- }
- else
- {
- intersection[starting_at].turn.instruction = {
- findBasicTurnType(via_edge, intersection[starting_at]), first_direction};
- handleDistinctConflict(via_edge, intersection[starting_at + 2],
- intersection[starting_at + 1]);
- }
- }
-
- else if ((first_direction == second_direction &&
- intersection[starting_at].entry_allowed !=
- intersection[starting_at + 1].entry_allowed) ||
- (second_direction == third_direction &&
- intersection[starting_at + 1].entry_allowed !=
- intersection[starting_at + 2].entry_allowed))
- {
- // no conflict, due to conflict being restricted to valid/invalid
- if (intersection[starting_at].entry_allowed)
- intersection[starting_at].turn.instruction = {
- findBasicTurnType(via_edge, intersection[starting_at]), first_direction};
- if (intersection[starting_at + 1].entry_allowed)
- intersection[starting_at + 1].turn.instruction = {
- findBasicTurnType(via_edge, intersection[starting_at + 1]), second_direction};
- if (intersection[starting_at + 2].entry_allowed)
- intersection[starting_at + 2].turn.instruction = {
- findBasicTurnType(via_edge, intersection[starting_at + 2]), third_direction};
- }
- else
- {
- auto coord = localizer(node_based_graph.GetTarget(via_edge));
- util::SimpleLogger().Write(logWARNING)
- << "Reached fallback for left turns, size 3: " << std::setprecision(12)
- << toFloating(coord.lat) << " " << toFloating(coord.lon);
- for (const auto road : intersection)
- {
- const auto &out_data = node_based_graph.GetEdgeData(road.turn.eid);
- util::SimpleLogger().Write(logWARNING)
- << "\troad: " << road.toString() << " Name: " << out_data.name_id
- << " Road Class: " << (int)out_data.road_classification.road_class
- << " At: " << localizer(node_based_graph.GetTarget(road.turn.eid));
- }
-
- for (std::size_t i = starting_at; i < intersection.size(); ++i)
- if (intersection[i].entry_allowed)
- intersection[i].turn.instruction = {
- findBasicTurnType(via_edge, intersection[i]),
- getTurnDirection(intersection[i].turn.angle)};
- }
- }
- else if (intersection.size() - starting_at == 4)
- {
- if (intersection[starting_at].entry_allowed)
- intersection[starting_at].turn.instruction = {
- detail::isRampClass(intersection[starting_at].turn.eid, node_based_graph)
- ? FirstRamp
- : FirstTurn,
- DirectionModifier::Left};
- if (intersection[starting_at + 1].entry_allowed)
- intersection[starting_at + 1].turn.instruction = {
- detail::isRampClass(intersection[starting_at + 1].turn.eid, node_based_graph)
- ? SecondRamp
- : SecondTurn,
- DirectionModifier::Left};
- if (intersection[starting_at + 2].entry_allowed)
- intersection[starting_at + 2].turn.instruction = {
- detail::isRampClass(intersection[starting_at + 2].turn.eid, node_based_graph)
- ? ThirdRamp
- : ThirdTurn,
- DirectionModifier::Left};
- if (intersection[starting_at + 3].entry_allowed)
- intersection[starting_at + 3].turn.instruction = {
- detail::isRampClass(intersection[starting_at + 3].turn.eid, node_based_graph)
- ? FourthRamp
- : FourthTurn,
- DirectionModifier::Left};
- }
- else
- {
- for (auto &road : intersection)
- {
- if (!road.entry_allowed)
- continue;
- road.turn.instruction = {detail::isRampClass(road.turn.eid, node_based_graph) ? Ramp
- : Turn,
- getTurnDirection(road.turn.angle)};
- }
- /*
- auto coord = localizer(node_based_graph.GetTarget(via_edge));
- util::SimpleLogger().Write(logWARNING)
- << "Reached fallback for left turns (" << starting_at << ") " << std::setprecision(12)
- << toFloating(coord.lat) << " " << toFloating(coord.lon);
- for (const auto road : intersection)
- {
- const auto &out_data = node_based_graph.GetEdgeData(road.turn.eid);
- util::SimpleLogger().Write(logWARNING)
- << "\troad: " << road.toString() << " Name: " << out_data.name_id
- << " Road Class: " << (int)out_data.road_classification.road_class
- << " At: " << localizer(node_based_graph.GetTarget(road.turn.eid));
- }
- */
- }
- return intersection;
-}
-
-// can only assign three turns
-std::vector<ConnectedRoad> TurnAnalysis::assignRightTurns(const EdgeID via_edge,
- std::vector<ConnectedRoad> intersection,
- const std::size_t up_to) const
-{
- BOOST_ASSERT(up_to <= intersection.size());
- const auto count_valid = [&intersection, up_to]()
- {
- std::size_t count = 0;
- for (std::size_t i = 1; i < up_to; ++i)
- if (intersection[i].entry_allowed)
- ++count;
- return count;
- };
- if (up_to <= 1 || count_valid() == 0)
- return intersection;
- // handle single turn
- if (up_to == 2)
- {
- if (angularDeviation(intersection[1].turn.angle, STRAIGHT_ANGLE) > NARROW_TURN_ANGLE &&
- angularDeviation(intersection[1].turn.angle, 0) > NARROW_TURN_ANGLE)
- {
- // assign left turn
- intersection[1].turn.instruction = {findBasicTurnType(via_edge, intersection[1]),
- DirectionModifier::Right};
- }
- else if (angularDeviation(intersection[1].turn.angle, STRAIGHT_ANGLE) <= NARROW_TURN_ANGLE)
- {
- intersection[1].turn.instruction = {findBasicTurnType(via_edge, intersection[1]),
- DirectionModifier::SlightRight};
- }
- else
- {
- intersection[1].turn.instruction = {findBasicTurnType(via_edge, intersection[1]),
- DirectionModifier::SharpRight};
- }
- }
- else if (up_to == 3)
- {
- const auto first_direction = getTurnDirection(intersection[1].turn.angle);
- const auto second_direction = getTurnDirection(intersection[2].turn.angle);
- if (first_direction == second_direction)
- {
- // conflict
- handleDistinctConflict(via_edge, intersection[2], intersection[1]);
- }
- else
- {
- intersection[1].turn.instruction = {findBasicTurnType(via_edge, intersection[1]),
- first_direction};
- intersection[2].turn.instruction = {findBasicTurnType(via_edge, intersection[2]),
- second_direction};
- }
- }
- else if (up_to == 4)
- {
- const auto first_direction = getTurnDirection(intersection[1].turn.angle);
- const auto second_direction = getTurnDirection(intersection[2].turn.angle);
- const auto third_direction = getTurnDirection(intersection[3].turn.angle);
- if (first_direction != second_direction && second_direction != third_direction)
- {
- if (intersection[1].entry_allowed)
- intersection[1].turn.instruction = {findBasicTurnType(via_edge, intersection[1]),
- first_direction};
- if (intersection[2].entry_allowed)
- intersection[2].turn.instruction = {findBasicTurnType(via_edge, intersection[2]),
- second_direction};
- if (intersection[3].entry_allowed)
- intersection[3].turn.instruction = {findBasicTurnType(via_edge, intersection[3]),
- third_direction};
- }
- else if (2 >= (intersection[1].entry_allowed + intersection[2].entry_allowed +
- intersection[3].entry_allowed))
- {
- // at least a single invalid
- if (!intersection[3].entry_allowed)
- {
- handleDistinctConflict(via_edge, intersection[2], intersection[1]);
- }
- else if (!intersection[1].entry_allowed)
- {
- handleDistinctConflict(via_edge, intersection[3], intersection[2]);
- }
- else // handles one-valid as well as two valid (1,3)
- {
- handleDistinctConflict(via_edge, intersection[3], intersection[1]);
- }
- }
-
- else if (intersection[1].entry_allowed && intersection[2].entry_allowed &&
- intersection[3].entry_allowed &&
- angularDeviation(intersection[1].turn.angle, intersection[2].turn.angle) >=
- NARROW_TURN_ANGLE &&
- angularDeviation(intersection[2].turn.angle, intersection[3].turn.angle) >=
- NARROW_TURN_ANGLE)
- {
- intersection[1].turn.instruction = {findBasicTurnType(via_edge, intersection[1]),
- DirectionModifier::SharpRight};
- intersection[2].turn.instruction = {findBasicTurnType(via_edge, intersection[2]),
- DirectionModifier::Right};
- intersection[3].turn.instruction = {findBasicTurnType(via_edge, intersection[3]),
- DirectionModifier::SlightRight};
- }
- else if (intersection[1].entry_allowed && intersection[2].entry_allowed &&
- intersection[3].entry_allowed &&
- ((first_direction == second_direction && second_direction == third_direction) ||
- (first_direction == second_direction &&
- angularDeviation(intersection[2].turn.angle, intersection[3].turn.angle) <
- GROUP_ANGLE) ||
- (second_direction == third_direction &&
- angularDeviation(intersection[1].turn.angle, intersection[2].turn.angle) <
- GROUP_ANGLE)))
- {
- intersection[1].turn.instruction = {
- detail::isRampClass(intersection[1].turn.eid, node_based_graph) ? ThirdRamp
- : ThirdTurn,
- second_direction};
- intersection[2].turn.instruction = {
- detail::isRampClass(intersection[2].turn.eid, node_based_graph) ? SecondRamp
- : SecondTurn,
- second_direction};
- intersection[3].turn.instruction = {
- detail::isRampClass(intersection[3].turn.eid, node_based_graph) ? FirstRamp
- : FirstTurn,
- second_direction};
- }
- else if (intersection[1].entry_allowed && intersection[2].entry_allowed &&
- intersection[3].entry_allowed &&
- ((first_direction == second_direction &&
- angularDeviation(intersection[2].turn.angle, intersection[3].turn.angle) >=
- GROUP_ANGLE) ||
- (second_direction == third_direction &&
- angularDeviation(intersection[1].turn.angle, intersection[2].turn.angle) >=
- GROUP_ANGLE)))
- {
- if (angularDeviation(intersection[2].turn.angle, intersection[3].turn.angle) >=
- GROUP_ANGLE)
- {
- handleDistinctConflict(via_edge, intersection[2], intersection[1]);
- intersection[3].turn.instruction = {findBasicTurnType(via_edge, intersection[3]),
- third_direction};
- }
- else
- {
- intersection[1].turn.instruction = {findBasicTurnType(via_edge, intersection[1]),
- first_direction};
- handleDistinctConflict(via_edge, intersection[3], intersection[2]);
- }
- }
- else if ((first_direction == second_direction &&
- intersection[1].entry_allowed != intersection[2].entry_allowed) ||
- (second_direction == third_direction &&
- intersection[2].entry_allowed != intersection[3].entry_allowed))
- {
- if (intersection[1].entry_allowed)
- intersection[1].turn.instruction = {findBasicTurnType(via_edge, intersection[1]),
- first_direction};
- if (intersection[2].entry_allowed)
- intersection[2].turn.instruction = {findBasicTurnType(via_edge, intersection[2]),
- second_direction};
- if (intersection[3].entry_allowed)
- intersection[3].turn.instruction = {findBasicTurnType(via_edge, intersection[3]),
- third_direction};
- }
- else
- {
- auto coord = localizer(node_based_graph.GetTarget(via_edge));
- util::SimpleLogger().Write(logWARNING)
- << "Reached fallback for right turns, size 3: " << std::setprecision(12)
- << toFloating(coord.lat) << " " << toFloating(coord.lon)
- << " Valids: " << (intersection[1].entry_allowed + intersection[2].entry_allowed +
- intersection[3].entry_allowed);
- for (const auto road : intersection)
- {
- const auto &out_data = node_based_graph.GetEdgeData(road.turn.eid);
- util::SimpleLogger().Write(logWARNING)
- << "\troad: " << road.toString() << " Name: " << out_data.name_id
- << " Road Class: " << (int)out_data.road_classification.road_class
- << " At: " << localizer(node_based_graph.GetTarget(road.turn.eid));
- }
-
- for (std::size_t i = 1; i < up_to; ++i)
- if (intersection[i].entry_allowed)
- intersection[i].turn.instruction = {
- findBasicTurnType(via_edge, intersection[i]),
- getTurnDirection(intersection[i].turn.angle)};
- }
- }
- else if (up_to == 5)
- {
- if (intersection[4].entry_allowed)
- intersection[4].turn.instruction = {
- detail::isRampClass(intersection[4].turn.eid, node_based_graph) ? FirstRamp
- : FirstTurn,
- DirectionModifier::Right};
- if (intersection[3].entry_allowed)
- intersection[3].turn.instruction = {
- detail::isRampClass(intersection[3].turn.eid, node_based_graph) ? SecondRamp
- : SecondTurn,
- DirectionModifier::Right};
- if (intersection[2].entry_allowed)
- intersection[2].turn.instruction = {
- detail::isRampClass(intersection[2].turn.eid, node_based_graph) ? ThirdRamp
- : ThirdTurn,
- DirectionModifier::Right};
- if (intersection[1].entry_allowed)
- intersection[1].turn.instruction = {
- detail::isRampClass(intersection[1].turn.eid, node_based_graph) ? FourthRamp
- : FourthTurn,
- DirectionModifier::Right};
- }
- else
- {
- for (std::size_t i = 1; i < up_to; ++i)
- {
- auto &road = intersection[i];
- if (!road.entry_allowed)
- continue;
- road.turn.instruction = {detail::isRampClass(road.turn.eid, node_based_graph) ? Ramp
- : Turn,
- getTurnDirection(road.turn.angle)};
- }
-
- /*
- auto coord = localizer(node_based_graph.GetTarget(via_edge));
- util::SimpleLogger().Write(logWARNING)
- << "Reached fallback for right turns (" << up_to << ") " << std::setprecision(12)
- << toFloating(coord.lat) << " " << toFloating(coord.lon);
- for (const auto road : intersection)
- {
- const auto &out_data = node_based_graph.GetEdgeData(road.turn.eid);
- util::SimpleLogger().Write(logWARNING)
- << "\troad: " << road.toString() << " Name: " << out_data.name_id
- << " Road Class: " << (int)out_data.road_classification.road_class
- << " At: " << localizer(node_based_graph.GetTarget(road.turn.eid));
- }
- */
+ road.turn.instruction = {TurnType::Turn, (from_nid == to_nid)
+ ? DirectionModifier::UTurn
+ : getTurnDirection(road.turn.angle)};
}
return intersection;
}
diff --git a/src/extractor/guidance/turn_handler.cpp b/src/extractor/guidance/turn_handler.cpp
new file mode 100644
index 0000000..57a29d6
--- /dev/null
+++ b/src/extractor/guidance/turn_handler.cpp
@@ -0,0 +1,1171 @@
+#include "extractor/guidance/constants.hpp"
+#include "extractor/guidance/toolkit.hpp"
+#include "extractor/guidance/turn_handler.hpp"
+
+#include "util/simple_logger.hpp"
+
+#include <limits>
+#include <utility>
+
+#include <boost/assert.hpp>
+
+using EdgeData = osrm::util::NodeBasedDynamicGraph::EdgeData;
+
+namespace osrm
+{
+namespace extractor
+{
+namespace guidance
+{
+namespace detail
+{
+inline FunctionalRoadClass roadClass(const ConnectedRoad &road,
+ const util::NodeBasedDynamicGraph &graph)
+{
+ return graph.GetEdgeData(road.turn.eid).road_classification.road_class;
+}
+
+inline bool isRampClass(EdgeID eid, const util::NodeBasedDynamicGraph &node_based_graph)
+{
+ return isRampClass(node_based_graph.GetEdgeData(eid).road_classification.road_class);
+}
+}
+
+TurnHandler::TurnHandler(const util::NodeBasedDynamicGraph &node_based_graph,
+ const std::vector<QueryNode> &node_info_list,
+ const util::NameTable &name_table)
+ : IntersectionHandler(node_based_graph, node_info_list, name_table)
+{
+}
+
+TurnHandler::~TurnHandler() {}
+
+bool TurnHandler::canProcess(const NodeID, const EdgeID, const Intersection &) const
+{
+ return true;
+}
+
+Intersection TurnHandler::
+operator()(const NodeID, const EdgeID via_eid, Intersection intersection) const
+{
+ if (intersection.size() == 1)
+ return handleOneWayTurn(std::move(intersection));
+
+ if (intersection[0].entry_allowed)
+ {
+ intersection[0].turn.instruction = {findBasicTurnType(via_eid, intersection[0]),
+ DirectionModifier::UTurn};
+ }
+
+ if (intersection.size() == 2)
+ return handleTwoWayTurn(via_eid, std::move(intersection));
+
+ if (intersection.size() == 3)
+ return handleThreeWayTurn(via_eid, std::move(intersection));
+
+ return handleComplexTurn(via_eid, std::move(intersection));
+}
+
+Intersection TurnHandler::handleOneWayTurn(Intersection intersection) const
+{
+ BOOST_ASSERT(intersection[0].turn.angle < 0.001);
+ return intersection;
+}
+
+Intersection TurnHandler::handleTwoWayTurn(const EdgeID via_edge, Intersection intersection) const
+{
+ BOOST_ASSERT(intersection[0].turn.angle < 0.001);
+ intersection[1].turn.instruction =
+ 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;
+}
+
+Intersection TurnHandler::handleThreeWayTurn(const EdgeID via_edge, Intersection intersection) const
+{
+ BOOST_ASSERT(intersection[0].turn.angle < 0.001);
+ const auto isObviousOfTwo = [this](const ConnectedRoad road, const ConnectedRoad other) {
+ const auto first_class =
+ node_based_graph.GetEdgeData(road.turn.eid).road_classification.road_class;
+ const bool is_ramp = isRampClass(first_class);
+ const auto second_class =
+ node_based_graph.GetEdgeData(other.turn.eid).road_classification.road_class;
+ const bool is_narrow_turn =
+ angularDeviation(road.turn.angle, STRAIGHT_ANGLE) < NARROW_TURN_ANGLE;
+ const bool other_turn_is_at_least_orthogonal =
+ angularDeviation(other.turn.angle, STRAIGHT_ANGLE) > 85;
+ const bool turn_is_perfectly_straight = angularDeviation(road.turn.angle, STRAIGHT_ANGLE) <
+ std::numeric_limits<double>::epsilon();
+ const bool is_obvious_by_road_class =
+ (!is_ramp && (2 * getPriority(first_class) < getPriority(second_class))) ||
+ (!isLowPriorityRoadClass(first_class) && isLowPriorityRoadClass(second_class));
+ const bool is_much_narrower_than_other =
+ angularDeviation(other.turn.angle, STRAIGHT_ANGLE) /
+ angularDeviation(road.turn.angle, STRAIGHT_ANGLE) >
+ INCREASES_BY_FOURTY_PERCENT;
+ return (is_narrow_turn && other_turn_is_at_least_orthogonal) ||
+ turn_is_perfectly_straight || is_much_narrower_than_other ||
+ is_obvious_by_road_class;
+ };
+
+ /* Two nearly straight turns -> FORK
+ OOOOOOO
+ /
+ IIIIII
+ \
+ OOOOOOO
+ */
+ if (angularDeviation(intersection[1].turn.angle, STRAIGHT_ANGLE) < NARROW_TURN_ANGLE &&
+ angularDeviation(intersection[2].turn.angle, STRAIGHT_ANGLE) < NARROW_TURN_ANGLE)
+ {
+ if (intersection[1].entry_allowed && intersection[2].entry_allowed)
+ {
+ const auto left_class = node_based_graph.GetEdgeData(intersection[2].turn.eid)
+ .road_classification.road_class;
+ const auto right_class = node_based_graph.GetEdgeData(intersection[1].turn.eid)
+ .road_classification.road_class;
+ if (canBeSeenAsFork(left_class, right_class))
+ {
+ assignFork(via_edge, intersection[2], intersection[1]);
+ }
+ else if (isObviousOfTwo(intersection[1], intersection[2]))
+ {
+ intersection[1].turn.instruction =
+ getInstructionForObvious(intersection.size(), via_edge, false, intersection[1]);
+ intersection[2].turn.instruction = {findBasicTurnType(via_edge, intersection[2]),
+ DirectionModifier::SlightLeft};
+ }
+ else if (isObviousOfTwo(intersection[2], intersection[1]))
+ {
+ intersection[2].turn.instruction =
+ getInstructionForObvious(intersection.size(), via_edge, false, intersection[2]);
+ intersection[1].turn.instruction = {findBasicTurnType(via_edge, intersection[1]),
+ DirectionModifier::SlightRight};
+ }
+ else
+ {
+ intersection[1].turn.instruction = {findBasicTurnType(via_edge, intersection[1]),
+ DirectionModifier::SlightRight};
+ intersection[2].turn.instruction = {findBasicTurnType(via_edge, intersection[2]),
+ DirectionModifier::SlightLeft};
+ }
+ }
+ else
+ {
+ if (intersection[1].entry_allowed)
+ intersection[1].turn.instruction =
+ getInstructionForObvious(intersection.size(), via_edge, false, intersection[1]);
+ if (intersection[2].entry_allowed)
+ intersection[2].turn.instruction =
+ getInstructionForObvious(intersection.size(), via_edge, false, intersection[2]);
+ }
+ }
+ /* T Intersection
+
+ OOOOOOO T OOOOOOOO
+ I
+ I
+ I
+ */
+ else if (angularDeviation(intersection[1].turn.angle, 90) < NARROW_TURN_ANGLE &&
+ angularDeviation(intersection[2].turn.angle, 270) < NARROW_TURN_ANGLE &&
+ angularDeviation(intersection[1].turn.angle, intersection[2].turn.angle) >
+ NARROW_TURN_ANGLE)
+ {
+ if (intersection[1].entry_allowed)
+ {
+ if (TurnType::Ramp != findBasicTurnType(via_edge, intersection[1]))
+ intersection[1].turn.instruction = {TurnType::EndOfRoad, DirectionModifier::Right};
+ else
+ intersection[1].turn.instruction = {TurnType::Ramp, DirectionModifier::Right};
+ }
+ if (intersection[2].entry_allowed)
+ {
+ if (TurnType::Ramp != findBasicTurnType(via_edge, intersection[2]))
+
+ intersection[2].turn.instruction = {TurnType::EndOfRoad, DirectionModifier::Left};
+ else
+ intersection[2].turn.instruction = {TurnType::Ramp, DirectionModifier::Left};
+ }
+ }
+ /* T Intersection, Cross left
+ O
+ O
+ O
+ IIIIIIII - OOOOOOOOOO
+ */
+ else if (angularDeviation(intersection[1].turn.angle, STRAIGHT_ANGLE) < NARROW_TURN_ANGLE &&
+ angularDeviation(intersection[2].turn.angle, 270) < NARROW_TURN_ANGLE &&
+ angularDeviation(intersection[1].turn.angle, intersection[2].turn.angle) >
+ NARROW_TURN_ANGLE)
+ {
+ if (intersection[1].entry_allowed)
+ {
+ if (TurnType::Ramp != findBasicTurnType(via_edge, intersection[1]))
+ intersection[1].turn.instruction =
+ getInstructionForObvious(intersection.size(), via_edge, false, intersection[1]);
+ else
+ intersection[1].turn.instruction = {TurnType::Ramp, DirectionModifier::Straight};
+ }
+ if (intersection[2].entry_allowed)
+ {
+ intersection[2].turn.instruction = {findBasicTurnType(via_edge, intersection[2]),
+ DirectionModifier::Left};
+ }
+ }
+ /* T Intersection, Cross right
+
+ IIIIIIII T OOOOOOOOOO
+ O
+ O
+ O
+ */
+ else if (angularDeviation(intersection[2].turn.angle, STRAIGHT_ANGLE) < NARROW_TURN_ANGLE &&
+ angularDeviation(intersection[1].turn.angle, 90) < NARROW_TURN_ANGLE &&
+ angularDeviation(intersection[1].turn.angle, intersection[2].turn.angle) >
+ NARROW_TURN_ANGLE)
+ {
+ if (intersection[2].entry_allowed)
+ intersection[2].turn.instruction =
+ getInstructionForObvious(intersection.size(), via_edge, false, intersection[2]);
+ if (intersection[1].entry_allowed)
+ intersection[1].turn.instruction = {findBasicTurnType(via_edge, intersection[1]),
+ DirectionModifier::Right};
+ }
+ // merge onto a through street
+ else if (INVALID_NAME_ID != node_based_graph.GetEdgeData(intersection[1].turn.eid).name_id &&
+ node_based_graph.GetEdgeData(intersection[1].turn.eid).name_id ==
+ node_based_graph.GetEdgeData(intersection[2].turn.eid).name_id)
+ {
+ const auto findTurn = [isObviousOfTwo](const ConnectedRoad turn,
+ const ConnectedRoad other) -> TurnInstruction {
+ if (isObviousOfTwo(turn, other))
+ {
+ return {TurnType::Merge, turn.turn.angle < STRAIGHT_ANGLE
+ ? DirectionModifier::SlightLeft
+ : DirectionModifier::SlightRight};
+ }
+ else
+ {
+ return {TurnType::Turn, getTurnDirection(turn.turn.angle)};
+ }
+ };
+ intersection[1].turn.instruction = findTurn(intersection[1], intersection[2]);
+ intersection[2].turn.instruction = findTurn(intersection[2], intersection[1]);
+ }
+ // other street merges from the left
+ else if (INVALID_NAME_ID != node_based_graph.GetEdgeData(via_edge).name_id &&
+ node_based_graph.GetEdgeData(via_edge).name_id ==
+ node_based_graph.GetEdgeData(intersection[1].turn.eid).name_id)
+ {
+ if (isObviousOfTwo(intersection[1], intersection[2]))
+ {
+ intersection[1].turn.instruction =
+ TurnInstruction::SUPPRESSED(DirectionModifier::Straight);
+ }
+ else
+ {
+ intersection[1].turn.instruction = {TurnType::Continue,
+ getTurnDirection(intersection[1].turn.angle)};
+ }
+ intersection[2].turn.instruction = {findBasicTurnType(via_edge, intersection[2]),
+ getTurnDirection(intersection[2].turn.angle)};
+ }
+ // other street merges from the right
+ else if (INVALID_NAME_ID != node_based_graph.GetEdgeData(via_edge).name_id &&
+ node_based_graph.GetEdgeData(via_edge).name_id ==
+ node_based_graph.GetEdgeData(intersection[2].turn.eid).name_id)
+ {
+ if (isObviousOfTwo(intersection[2], intersection[1]))
+ {
+ intersection[2].turn.instruction =
+ TurnInstruction::SUPPRESSED(DirectionModifier::Straight);
+ }
+ else
+ {
+ intersection[2].turn.instruction = {TurnType::Continue,
+ getTurnDirection(intersection[2].turn.angle)};
+ }
+ intersection[1].turn.instruction = {findBasicTurnType(via_edge, intersection[1]),
+ getTurnDirection(intersection[1].turn.angle)};
+ }
+ else
+ {
+ if (isObviousOfTwo(intersection[1], intersection[2]))
+ {
+ intersection[1].turn.instruction =
+ getInstructionForObvious(3, via_edge, false, intersection[1]);
+ }
+ else
+ {
+ intersection[1].turn.instruction = {findBasicTurnType(via_edge, intersection[1]),
+ getTurnDirection(intersection[1].turn.angle)};
+ }
+
+ if (isObviousOfTwo(intersection[2], intersection[1]))
+ {
+ intersection[2].turn.instruction =
+ getInstructionForObvious(3, via_edge, false, intersection[2]);
+ }
+ else
+ {
+ intersection[2].turn.instruction = {findBasicTurnType(via_edge, intersection[2]),
+ getTurnDirection(intersection[2].turn.angle)};
+ }
+ }
+ return intersection;
+}
+
+Intersection TurnHandler::handleComplexTurn(const EdgeID via_edge, Intersection intersection) const
+{
+ static int fallback_count = 0;
+ const std::size_t obvious_index = findObviousTurn(via_edge, intersection);
+ const auto fork_range = findFork(intersection);
+ std::size_t straightmost_turn = 0;
+ double straightmost_deviation = 180;
+ for (std::size_t i = 0; i < intersection.size(); ++i)
+ {
+ const double deviation = angularDeviation(intersection[i].turn.angle, STRAIGHT_ANGLE);
+ if (deviation < straightmost_deviation)
+ {
+ straightmost_deviation = deviation;
+ straightmost_turn = i;
+ }
+ }
+
+ // check whether the obvious choice is actually a through street
+ if (obvious_index != 0)
+ {
+ intersection[obvious_index].turn.instruction =
+ getInstructionForObvious(intersection.size(), via_edge, isThroughStreet(obvious_index,intersection),
+ intersection[obvious_index]);
+
+ // assign left/right turns
+ intersection = assignLeftTurns(via_edge, std::move(intersection), obvious_index + 1);
+ intersection = assignRightTurns(via_edge, std::move(intersection), obvious_index);
+ }
+ else if (fork_range.first != 0 && fork_range.second - fork_range.first <= 2) // found fork
+ {
+ if (fork_range.second - fork_range.first == 1)
+ {
+ auto &left = intersection[fork_range.second];
+ auto &right = intersection[fork_range.first];
+ const auto left_class =
+ node_based_graph.GetEdgeData(left.turn.eid).road_classification.road_class;
+ const auto right_class =
+ node_based_graph.GetEdgeData(right.turn.eid).road_classification.road_class;
+ if (canBeSeenAsFork(left_class, right_class))
+ assignFork(via_edge, left, right);
+ else if (getPriority(left_class) > getPriority(right_class))
+ {
+ right.turn.instruction =
+ getInstructionForObvious(intersection.size(), via_edge, false, right);
+ left.turn.instruction = {findBasicTurnType(via_edge, left),
+ DirectionModifier::SlightLeft};
+ }
+ else
+ {
+ left.turn.instruction =
+ getInstructionForObvious(intersection.size(), via_edge, false, left);
+ right.turn.instruction = {findBasicTurnType(via_edge, right),
+ DirectionModifier::SlightRight};
+ }
+ }
+ else if (fork_range.second - fork_range.second == 2)
+ {
+ assignFork(via_edge, intersection[fork_range.second],
+ intersection[fork_range.first + 1], intersection[fork_range.first]);
+ }
+ // assign left/right turns
+ intersection = assignLeftTurns(via_edge, std::move(intersection), fork_range.second + 1);
+ intersection = assignRightTurns(via_edge, std::move(intersection), fork_range.first);
+ }
+ else if (straightmost_deviation < FUZZY_ANGLE_DIFFERENCE &&
+ !intersection[straightmost_turn].entry_allowed)
+ {
+ // invalid straight turn
+ intersection = assignLeftTurns(via_edge, std::move(intersection), straightmost_turn + 1);
+ intersection = assignRightTurns(via_edge, std::move(intersection), straightmost_turn);
+ }
+ // no straight turn
+ else if (intersection[straightmost_turn].turn.angle > 180)
+ {
+ // at most three turns on either side
+ intersection = assignLeftTurns(via_edge, std::move(intersection), straightmost_turn);
+ intersection = assignRightTurns(via_edge, std::move(intersection), straightmost_turn);
+ }
+ else if (intersection[straightmost_turn].turn.angle < 180)
+ {
+ intersection = assignLeftTurns(via_edge, std::move(intersection), straightmost_turn + 1);
+ intersection = assignRightTurns(via_edge, std::move(intersection), straightmost_turn + 1);
+ }
+ else
+ {
+ if (fallback_count++ < 10)
+ {
+ util::SimpleLogger().Write(logWARNING)
+ << "Resolved to keep fallback on complex turn assignment"
+ << "Straightmost: " << straightmost_turn;
+ ;
+ for (const auto &road : intersection)
+ {
+ const auto &out_data = node_based_graph.GetEdgeData(road.turn.eid);
+ util::SimpleLogger().Write(logWARNING)
+ << "road: " << toString(road) << " Name: " << out_data.name_id
+ << " Road Class: " << (int)out_data.road_classification.road_class;
+ }
+ }
+ }
+ return intersection;
+}
+
+std::size_t TurnHandler::findObviousTurn(const EdgeID via_edge,
+ const Intersection &intersection) const
+{
+ // no obvious road
+ if (intersection.size() == 1)
+ return 0;
+
+ // a single non u-turn is obvious
+ if (intersection.size() == 2)
+ return 1;
+
+ // at least three roads
+ std::size_t best = 0;
+ double best_deviation = 180;
+
+ std::size_t best_continue = 0;
+ double best_continue_deviation = 180;
+
+ const EdgeData &in_data = node_based_graph.GetEdgeData(via_edge);
+ for (std::size_t i = 1; i < intersection.size(); ++i)
+ {
+ const double deviation = angularDeviation(intersection[i].turn.angle, STRAIGHT_ANGLE);
+ if (intersection[i].entry_allowed && deviation < best_deviation)
+ {
+ best_deviation = deviation;
+ best = i;
+ }
+
+ const auto out_data = node_based_graph.GetEdgeData(intersection[i].turn.eid);
+ if (intersection[i].entry_allowed && out_data.name_id == in_data.name_id &&
+ deviation < best_continue_deviation)
+ {
+ best_continue_deviation = deviation;
+ best_continue = i;
+ }
+ }
+
+ if (best == 0)
+ return 0;
+
+ if (best_deviation >= 2 * NARROW_TURN_ANGLE)
+ return 0;
+
+ // TODO incorporate road class in decision
+ if (best != 0 && best_deviation < MAXIMAL_ALLOWED_NO_TURN_DEVIATION)
+ {
+ return best;
+ }
+
+ // has no obvious continued road
+ if (best_continue == 0 || true)
+ {
+ // Find left/right deviation
+ const double left_deviation = angularDeviation(
+ intersection[(best + 1) % intersection.size()].turn.angle, STRAIGHT_ANGLE);
+ const double right_deviation =
+ angularDeviation(intersection[best - 1].turn.angle, STRAIGHT_ANGLE);
+
+ if (best_deviation < MAXIMAL_ALLOWED_NO_TURN_DEVIATION &&
+ std::min(left_deviation, right_deviation) > FUZZY_ANGLE_DIFFERENCE)
+ return best;
+
+ // other narrow turns?
+ if (angularDeviation(intersection[best - 1].turn.angle, STRAIGHT_ANGLE) <=
+ FUZZY_ANGLE_DIFFERENCE)
+ return 0;
+ if (angularDeviation(intersection[(best + 1) % intersection.size()].turn.angle,
+ STRAIGHT_ANGLE) <= FUZZY_ANGLE_DIFFERENCE)
+ return 0;
+
+ // Well distinct turn that is nearly straight
+ if (left_deviation / best_deviation >= DISTINCTION_RATIO &&
+ right_deviation / best_deviation >= DISTINCTION_RATIO)
+ {
+ return best;
+ }
+ }
+
+ return 0; // no obvious turn
+}
+
+// Can only assign three turns
+Intersection TurnHandler::assignLeftTurns(const EdgeID via_edge,
+ Intersection intersection,
+ const std::size_t starting_at) const
+{
+ const auto count_valid = [&intersection, starting_at]() {
+ std::size_t count = 0;
+ for (std::size_t i = starting_at; i < intersection.size(); ++i)
+ if (intersection[i].entry_allowed)
+ ++count;
+ return count;
+ };
+ if (starting_at == intersection.size() || count_valid() == 0)
+ return intersection;
+ // handle single turn
+ if (intersection.size() - starting_at == 1)
+ {
+ if (!intersection[starting_at].entry_allowed)
+ return intersection;
+
+ if (angularDeviation(intersection[starting_at].turn.angle, STRAIGHT_ANGLE) >
+ NARROW_TURN_ANGLE &&
+ angularDeviation(intersection[starting_at].turn.angle, 0) > NARROW_TURN_ANGLE)
+ {
+ // assign left turn
+ intersection[starting_at].turn.instruction = {
+ findBasicTurnType(via_edge, intersection[starting_at]), DirectionModifier::Left};
+ }
+ else if (angularDeviation(intersection[starting_at].turn.angle, STRAIGHT_ANGLE) <=
+ NARROW_TURN_ANGLE)
+ {
+ intersection[starting_at].turn.instruction = {
+ findBasicTurnType(via_edge, intersection[starting_at]),
+ DirectionModifier::SlightLeft};
+ }
+ else
+ {
+ intersection[starting_at].turn.instruction = {
+ findBasicTurnType(via_edge, intersection[starting_at]),
+ DirectionModifier::SharpLeft};
+ }
+ }
+ // two turns on at the side
+ else if (intersection.size() - starting_at == 2)
+ {
+ const auto first_direction = getTurnDirection(intersection[starting_at].turn.angle);
+ const auto second_direction = getTurnDirection(intersection[starting_at + 1].turn.angle);
+ if (first_direction == second_direction)
+ {
+ // conflict
+ handleDistinctConflict(via_edge, intersection[starting_at + 1],
+ intersection[starting_at]);
+ }
+ else
+ {
+ intersection[starting_at].turn.instruction = {
+ findBasicTurnType(via_edge, intersection[starting_at]), first_direction};
+ intersection[starting_at + 1].turn.instruction = {
+ findBasicTurnType(via_edge, intersection[starting_at + 1]), second_direction};
+ }
+ }
+ else if (intersection.size() - starting_at == 3)
+ {
+ const auto first_direction = getTurnDirection(intersection[starting_at].turn.angle);
+ const auto second_direction = getTurnDirection(intersection[starting_at + 1].turn.angle);
+ const auto third_direction = getTurnDirection(intersection[starting_at + 2].turn.angle);
+ if (first_direction != second_direction && second_direction != third_direction)
+ {
+ // implies first != third, based on the angles and clockwise order
+ if (intersection[starting_at].entry_allowed)
+ intersection[starting_at].turn.instruction = {
+ findBasicTurnType(via_edge, intersection[starting_at]), first_direction};
+ if (intersection[starting_at + 1].entry_allowed)
+ intersection[starting_at + 1].turn.instruction = {
+ findBasicTurnType(via_edge, intersection[starting_at + 1]), second_direction};
+ if (intersection[starting_at + 2].entry_allowed)
+ intersection[starting_at + 2].turn.instruction = {
+ findBasicTurnType(via_edge, intersection[starting_at + 2]), third_direction};
+ }
+ else if (2 >= (intersection[starting_at].entry_allowed +
+ intersection[starting_at + 1].entry_allowed +
+ intersection[starting_at + 2].entry_allowed))
+ {
+
+ // at least one invalid turn
+ if (!intersection[starting_at].entry_allowed)
+ {
+ handleDistinctConflict(via_edge, intersection[starting_at + 2],
+ intersection[starting_at + 1]);
+ }
+ else if (!intersection[starting_at + 1].entry_allowed)
+ {
+ handleDistinctConflict(via_edge, intersection[starting_at + 2],
+ intersection[starting_at]);
+ }
+ else
+ {
+ handleDistinctConflict(via_edge, intersection[starting_at + 1],
+ intersection[starting_at]);
+ }
+ }
+ else if (intersection[starting_at].entry_allowed &&
+ intersection[starting_at + 1].entry_allowed &&
+ intersection[starting_at + 2].entry_allowed &&
+ angularDeviation(intersection[starting_at].turn.angle,
+ intersection[starting_at + 1].turn.angle) >= NARROW_TURN_ANGLE &&
+ angularDeviation(intersection[starting_at + 1].turn.angle,
+ intersection[starting_at + 2].turn.angle) >= NARROW_TURN_ANGLE)
+ {
+ intersection[starting_at].turn.instruction = {
+ findBasicTurnType(via_edge, intersection[starting_at]),
+ DirectionModifier::SlightLeft};
+ intersection[starting_at + 1].turn.instruction = {
+ findBasicTurnType(via_edge, intersection[starting_at + 1]),
+ DirectionModifier::Left};
+ intersection[starting_at + 2].turn.instruction = {
+ findBasicTurnType(via_edge, intersection[starting_at + 2]),
+ DirectionModifier::SharpLeft};
+ }
+ else if (intersection[starting_at].entry_allowed &&
+ intersection[starting_at + 1].entry_allowed &&
+ intersection[starting_at + 2].entry_allowed &&
+ ((first_direction == second_direction && second_direction == third_direction) ||
+ (third_direction == second_direction &&
+ angularDeviation(intersection[starting_at].turn.angle,
+ intersection[starting_at + 1].turn.angle) < GROUP_ANGLE) ||
+ (second_direction == first_direction &&
+ angularDeviation(intersection[starting_at + 1].turn.angle,
+ intersection[starting_at + 2].turn.angle) < GROUP_ANGLE)))
+ {
+ intersection[starting_at].turn.instruction = {
+ detail::isRampClass(intersection[starting_at].turn.eid, node_based_graph)
+ ? FirstRamp
+ : FirstTurn,
+ second_direction};
+ intersection[starting_at + 1].turn.instruction = {
+ detail::isRampClass(intersection[starting_at + 1].turn.eid, node_based_graph)
+ ? SecondRamp
+ : SecondTurn,
+ second_direction};
+ intersection[starting_at + 2].turn.instruction = {
+ detail::isRampClass(intersection[starting_at + 2].turn.eid, node_based_graph)
+ ? ThirdRamp
+ : ThirdTurn,
+ second_direction};
+ }
+ else if (intersection[starting_at].entry_allowed &&
+ intersection[starting_at + 1].entry_allowed &&
+ intersection[starting_at + 2].entry_allowed &&
+ ((third_direction == second_direction &&
+ angularDeviation(intersection[starting_at].turn.angle,
+ intersection[starting_at + 1].turn.angle) >= GROUP_ANGLE) ||
+ (second_direction == first_direction &&
+ angularDeviation(intersection[starting_at + 1].turn.angle,
+ intersection[starting_at + 2].turn.angle) >= GROUP_ANGLE)))
+ {
+ // conflict one side with an additional very sharp turn
+ if (angularDeviation(intersection[starting_at + 1].turn.angle,
+ intersection[starting_at + 2].turn.angle) >= GROUP_ANGLE)
+ {
+ handleDistinctConflict(via_edge, intersection[starting_at + 1],
+ intersection[starting_at]);
+ intersection[starting_at + 2].turn.instruction = {
+ findBasicTurnType(via_edge, intersection[starting_at + 2]), third_direction};
+ }
+ else
+ {
+ intersection[starting_at].turn.instruction = {
+ findBasicTurnType(via_edge, intersection[starting_at]), first_direction};
+ handleDistinctConflict(via_edge, intersection[starting_at + 2],
+ intersection[starting_at + 1]);
+ }
+ }
+ else if ((first_direction == second_direction &&
+ intersection[starting_at].entry_allowed !=
+ intersection[starting_at + 1].entry_allowed) ||
+ (second_direction == third_direction &&
+ intersection[starting_at + 1].entry_allowed !=
+ intersection[starting_at + 2].entry_allowed))
+ {
+ // no conflict, due to conflict being restricted to valid/invalid
+ if (intersection[starting_at].entry_allowed)
+ intersection[starting_at].turn.instruction = {
+ findBasicTurnType(via_edge, intersection[starting_at]), first_direction};
+ if (intersection[starting_at + 1].entry_allowed)
+ intersection[starting_at + 1].turn.instruction = {
+ findBasicTurnType(via_edge, intersection[starting_at + 1]), second_direction};
+ if (intersection[starting_at + 2].entry_allowed)
+ intersection[starting_at + 2].turn.instruction = {
+ findBasicTurnType(via_edge, intersection[starting_at + 2]), third_direction};
+ }
+ else
+ {
+ util::SimpleLogger().Write(logWARNING) << "Reached fallback for left turns, size 3";
+ for (const auto road : intersection)
+ {
+ const auto &out_data = node_based_graph.GetEdgeData(road.turn.eid);
+ util::SimpleLogger().Write(logWARNING)
+ << "\troad: " << toString(road) << " Name: " << out_data.name_id
+ << " Road Class: " << (int)out_data.road_classification.road_class;
+ }
+
+ for (std::size_t i = starting_at; i < intersection.size(); ++i)
+ if (intersection[i].entry_allowed)
+ intersection[i].turn.instruction = {
+ findBasicTurnType(via_edge, intersection[i]),
+ getTurnDirection(intersection[i].turn.angle)};
+ }
+ }
+ else if (intersection.size() - starting_at == 4)
+ {
+ if (intersection[starting_at].entry_allowed)
+ intersection[starting_at].turn.instruction = {
+ detail::isRampClass(intersection[starting_at].turn.eid, node_based_graph)
+ ? FirstRamp
+ : FirstTurn,
+ DirectionModifier::Left};
+ if (intersection[starting_at + 1].entry_allowed)
+ intersection[starting_at + 1].turn.instruction = {
+ detail::isRampClass(intersection[starting_at + 1].turn.eid, node_based_graph)
+ ? SecondRamp
+ : SecondTurn,
+ DirectionModifier::Left};
+ if (intersection[starting_at + 2].entry_allowed)
+ intersection[starting_at + 2].turn.instruction = {
+ detail::isRampClass(intersection[starting_at + 2].turn.eid, node_based_graph)
+ ? ThirdRamp
+ : ThirdTurn,
+ DirectionModifier::Left};
+ if (intersection[starting_at + 3].entry_allowed)
+ intersection[starting_at + 3].turn.instruction = {
+ detail::isRampClass(intersection[starting_at + 3].turn.eid, node_based_graph)
+ ? FourthRamp
+ : FourthTurn,
+ DirectionModifier::Left};
+ }
+ else
+ {
+ for (auto &road : intersection)
+ {
+ if (!road.entry_allowed)
+ continue;
+ road.turn.instruction = {detail::isRampClass(road.turn.eid, node_based_graph) ? Ramp
+ : Turn,
+ getTurnDirection(road.turn.angle)};
+ }
+ }
+ return intersection;
+}
+
+// can only assign three turns
+Intersection TurnHandler::assignRightTurns(const EdgeID via_edge,
+ Intersection intersection,
+ const std::size_t up_to) const
+{
+ BOOST_ASSERT(up_to <= intersection.size());
+ const auto count_valid = [&intersection, up_to]() {
+ std::size_t count = 0;
+ for (std::size_t i = 1; i < up_to; ++i)
+ if (intersection[i].entry_allowed)
+ ++count;
+ return count;
+ };
+ if (up_to <= 1 || count_valid() == 0)
+ return intersection;
+ // handle single turn
+ if (up_to == 2)
+ {
+ if (angularDeviation(intersection[1].turn.angle, STRAIGHT_ANGLE) > NARROW_TURN_ANGLE &&
+ angularDeviation(intersection[1].turn.angle, 0) > NARROW_TURN_ANGLE)
+ {
+ // assign left turn
+ intersection[1].turn.instruction = {findBasicTurnType(via_edge, intersection[1]),
+ DirectionModifier::Right};
+ }
+ else if (angularDeviation(intersection[1].turn.angle, STRAIGHT_ANGLE) <= NARROW_TURN_ANGLE)
+ {
+ intersection[1].turn.instruction = {findBasicTurnType(via_edge, intersection[1]),
+ DirectionModifier::SlightRight};
+ }
+ else
+ {
+ intersection[1].turn.instruction = {findBasicTurnType(via_edge, intersection[1]),
+ DirectionModifier::SharpRight};
+ }
+ }
+ else if (up_to == 3)
+ {
+ const auto first_direction = getTurnDirection(intersection[1].turn.angle);
+ const auto second_direction = getTurnDirection(intersection[2].turn.angle);
+ if (first_direction == second_direction)
+ {
+ // conflict
+ handleDistinctConflict(via_edge, intersection[2], intersection[1]);
+ }
+ else
+ {
+ intersection[1].turn.instruction = {findBasicTurnType(via_edge, intersection[1]),
+ first_direction};
+ intersection[2].turn.instruction = {findBasicTurnType(via_edge, intersection[2]),
+ second_direction};
+ }
+ }
+ else if (up_to == 4)
+ {
+ const auto first_direction = getTurnDirection(intersection[1].turn.angle);
+ const auto second_direction = getTurnDirection(intersection[2].turn.angle);
+ const auto third_direction = getTurnDirection(intersection[3].turn.angle);
+ if (first_direction != second_direction && second_direction != third_direction)
+ {
+ if (intersection[1].entry_allowed)
+ intersection[1].turn.instruction = {findBasicTurnType(via_edge, intersection[1]),
+ first_direction};
+ if (intersection[2].entry_allowed)
+ intersection[2].turn.instruction = {findBasicTurnType(via_edge, intersection[2]),
+ second_direction};
+ if (intersection[3].entry_allowed)
+ intersection[3].turn.instruction = {findBasicTurnType(via_edge, intersection[3]),
+ third_direction};
+ }
+ else if (2 >= (intersection[1].entry_allowed + intersection[2].entry_allowed +
+ intersection[3].entry_allowed))
+ {
+ // at least a single invalid
+ if (!intersection[3].entry_allowed)
+ {
+ handleDistinctConflict(via_edge, intersection[2], intersection[1]);
+ }
+ else if (!intersection[1].entry_allowed)
+ {
+ handleDistinctConflict(via_edge, intersection[3], intersection[2]);
+ }
+ else // handles one-valid as well as two valid (1,3)
+ {
+ handleDistinctConflict(via_edge, intersection[3], intersection[1]);
+ }
+ }
+ else if (intersection[1].entry_allowed && intersection[2].entry_allowed &&
+ intersection[3].entry_allowed &&
+ angularDeviation(intersection[1].turn.angle, intersection[2].turn.angle) >=
+ NARROW_TURN_ANGLE &&
+ angularDeviation(intersection[2].turn.angle, intersection[3].turn.angle) >=
+ NARROW_TURN_ANGLE)
+ {
+ intersection[1].turn.instruction = {findBasicTurnType(via_edge, intersection[1]),
+ DirectionModifier::SharpRight};
+ intersection[2].turn.instruction = {findBasicTurnType(via_edge, intersection[2]),
+ DirectionModifier::Right};
+ intersection[3].turn.instruction = {findBasicTurnType(via_edge, intersection[3]),
+ DirectionModifier::SlightRight};
+ }
+ else if (intersection[1].entry_allowed && intersection[2].entry_allowed &&
+ intersection[3].entry_allowed &&
+ ((first_direction == second_direction && second_direction == third_direction) ||
+ (first_direction == second_direction &&
+ angularDeviation(intersection[2].turn.angle, intersection[3].turn.angle) <
+ GROUP_ANGLE) ||
+ (second_direction == third_direction &&
+ angularDeviation(intersection[1].turn.angle, intersection[2].turn.angle) <
+ GROUP_ANGLE)))
+ {
+ intersection[1].turn.instruction = {
+ detail::isRampClass(intersection[1].turn.eid, node_based_graph) ? ThirdRamp
+ : ThirdTurn,
+ second_direction};
+ intersection[2].turn.instruction = {
+ detail::isRampClass(intersection[2].turn.eid, node_based_graph) ? SecondRamp
+ : SecondTurn,
+ second_direction};
+ intersection[3].turn.instruction = {
+ detail::isRampClass(intersection[3].turn.eid, node_based_graph) ? FirstRamp
+ : FirstTurn,
+ second_direction};
+ }
+ else if (intersection[1].entry_allowed && intersection[2].entry_allowed &&
+ intersection[3].entry_allowed &&
+ ((first_direction == second_direction &&
+ angularDeviation(intersection[2].turn.angle, intersection[3].turn.angle) >=
+ GROUP_ANGLE) ||
+ (second_direction == third_direction &&
+ angularDeviation(intersection[1].turn.angle, intersection[2].turn.angle) >=
+ GROUP_ANGLE)))
+ {
+ if (angularDeviation(intersection[2].turn.angle, intersection[3].turn.angle) >=
+ GROUP_ANGLE)
+ {
+ handleDistinctConflict(via_edge, intersection[2], intersection[1]);
+ intersection[3].turn.instruction = {findBasicTurnType(via_edge, intersection[3]),
+ third_direction};
+ }
+ else
+ {
+ intersection[1].turn.instruction = {findBasicTurnType(via_edge, intersection[1]),
+ first_direction};
+ handleDistinctConflict(via_edge, intersection[3], intersection[2]);
+ }
+ }
+ else if ((first_direction == second_direction &&
+ intersection[1].entry_allowed != intersection[2].entry_allowed) ||
+ (second_direction == third_direction &&
+ intersection[2].entry_allowed != intersection[3].entry_allowed))
+ {
+ if (intersection[1].entry_allowed)
+ intersection[1].turn.instruction = {findBasicTurnType(via_edge, intersection[1]),
+ first_direction};
+ if (intersection[2].entry_allowed)
+ intersection[2].turn.instruction = {findBasicTurnType(via_edge, intersection[2]),
+ second_direction};
+ if (intersection[3].entry_allowed)
+ intersection[3].turn.instruction = {findBasicTurnType(via_edge, intersection[3]),
+ third_direction};
+ }
+ else
+ {
+ util::SimpleLogger().Write(logWARNING)
+ << "Reached fallback for right turns, size 3 "
+ << " Valids: " << (intersection[1].entry_allowed + intersection[2].entry_allowed +
+ intersection[3].entry_allowed);
+ for (const auto road : intersection)
+ {
+ const auto &out_data = node_based_graph.GetEdgeData(road.turn.eid);
+ util::SimpleLogger().Write(logWARNING)
+ << "\troad: " << toString(road) << " Name: " << out_data.name_id
+ << " Road Class: " << (int)out_data.road_classification.road_class;
+ }
+
+ for (std::size_t i = 1; i < up_to; ++i)
+ if (intersection[i].entry_allowed)
+ intersection[i].turn.instruction = {
+ findBasicTurnType(via_edge, intersection[i]),
+ getTurnDirection(intersection[i].turn.angle)};
+ }
+ }
+ else if (up_to == 5)
+ {
+ if (intersection[4].entry_allowed)
+ intersection[4].turn.instruction = {
+ detail::isRampClass(intersection[4].turn.eid, node_based_graph) ? FirstRamp
+ : FirstTurn,
+ DirectionModifier::Right};
+ if (intersection[3].entry_allowed)
+ intersection[3].turn.instruction = {
+ detail::isRampClass(intersection[3].turn.eid, node_based_graph) ? SecondRamp
+ : SecondTurn,
+ DirectionModifier::Right};
+ if (intersection[2].entry_allowed)
+ intersection[2].turn.instruction = {
+ detail::isRampClass(intersection[2].turn.eid, node_based_graph) ? ThirdRamp
+ : ThirdTurn,
+ DirectionModifier::Right};
+ if (intersection[1].entry_allowed)
+ intersection[1].turn.instruction = {
+ detail::isRampClass(intersection[1].turn.eid, node_based_graph) ? FourthRamp
+ : FourthTurn,
+ DirectionModifier::Right};
+ }
+ else
+ {
+ for (std::size_t i = 1; i < up_to; ++i)
+ {
+ auto &road = intersection[i];
+ if (!road.entry_allowed)
+ continue;
+ road.turn.instruction = {detail::isRampClass(road.turn.eid, node_based_graph) ? Ramp
+ : Turn,
+ getTurnDirection(road.turn.angle)};
+ }
+ }
+ return intersection;
+}
+
+std::pair<std::size_t, std::size_t> TurnHandler::findFork(const Intersection &intersection) const
+{
+
+ std::size_t best = 0;
+ double best_deviation = 180;
+
+ // TODO handle road classes
+ for (std::size_t i = 1; i < intersection.size(); ++i)
+ {
+ const double deviation = angularDeviation(intersection[i].turn.angle, STRAIGHT_ANGLE);
+ if (intersection[i].entry_allowed && deviation < best_deviation)
+ {
+ best_deviation = deviation;
+ best = i;
+ }
+ }
+ if (best_deviation <= NARROW_TURN_ANGLE)
+ {
+ std::size_t left = best, right = best;
+ if (intersection[left].turn.angle >= 180)
+ {
+ // due to best > 1, we can safely decrement right
+ --right;
+ if (angularDeviation(intersection[right].turn.angle, STRAIGHT_ANGLE) >
+ NARROW_TURN_ANGLE)
+ return std::make_pair(std::size_t{0}, std::size_t{0});
+ }
+ else
+ {
+ ++left;
+ if (left >= intersection.size() ||
+ angularDeviation(intersection[left].turn.angle, STRAIGHT_ANGLE) > NARROW_TURN_ANGLE)
+ return std::make_pair(std::size_t{0}, std::size_t{0});
+ }
+ while (left + 1 < intersection.size() &&
+ angularDeviation(intersection[left].turn.angle, intersection[left + 1].turn.angle) <
+ NARROW_TURN_ANGLE)
+ ++left;
+ while (right > 1 &&
+ angularDeviation(intersection[right].turn.angle,
+ intersection[right - 1].turn.angle) < NARROW_TURN_ANGLE)
+ --right;
+
+ // TODO check whether 2*NARROW_TURN is too large
+ if (right < left &&
+ angularDeviation(intersection[left].turn.angle,
+ intersection[(left + 1) % intersection.size()].turn.angle) >=
+ 2 * NARROW_TURN_ANGLE &&
+ angularDeviation(intersection[right].turn.angle, intersection[right - 1].turn.angle) >=
+ 2 * NARROW_TURN_ANGLE)
+ return std::make_pair(right, left);
+ }
+ return std::make_pair(std::size_t{0}, std::size_t{0});
+}
+
+void TurnHandler::handleDistinctConflict(const EdgeID via_edge,
+ ConnectedRoad &left,
+ ConnectedRoad &right) const
+{
+ // single turn of both is valid (don't change the valid one)
+ // or multiple identical angles -> bad OSM intersection
+ if ((!left.entry_allowed || !right.entry_allowed) || (left.turn.angle == right.turn.angle))
+ {
+ if (left.entry_allowed)
+ left.turn.instruction = {findBasicTurnType(via_edge, left),
+ getTurnDirection(left.turn.angle)};
+ if (right.entry_allowed)
+ right.turn.instruction = {findBasicTurnType(via_edge, right),
+ getTurnDirection(right.turn.angle)};
+ return;
+ }
+
+ if (getTurnDirection(left.turn.angle) == DirectionModifier::Straight ||
+ getTurnDirection(left.turn.angle) == DirectionModifier::SlightLeft ||
+ getTurnDirection(right.turn.angle) == DirectionModifier::SlightRight)
+ {
+ const auto left_class =
+ node_based_graph.GetEdgeData(left.turn.eid).road_classification.road_class;
+ const auto right_class =
+ node_based_graph.GetEdgeData(right.turn.eid).road_classification.road_class;
+ if (canBeSeenAsFork(left_class, right_class))
+ assignFork(via_edge, left, right);
+ else if (getPriority(left_class) > getPriority(right_class))
+ {
+ // FIXME this should possibly know about the actual roads?
+ // here we don't know about the intersection size. To be on the save side,
+ // we declare it
+ // as complex (at least size 4)
+ right.turn.instruction = getInstructionForObvious(4, via_edge, false, right);
+ left.turn.instruction = {findBasicTurnType(via_edge, left),
+ DirectionModifier::SlightLeft};
+ }
+ else
+ {
+ // FIXME this should possibly know about the actual roads?
+ // here we don't know about the intersection size. To be on the save side,
+ // we declare it
+ // as complex (at least size 4)
+ left.turn.instruction = getInstructionForObvious(4, via_edge, false, left);
+ right.turn.instruction = {findBasicTurnType(via_edge, right),
+ DirectionModifier::SlightRight};
+ }
+ }
+ const auto left_type = findBasicTurnType(via_edge, left);
+ const auto right_type = findBasicTurnType(via_edge, right);
+ // Two Right Turns
+ if (angularDeviation(left.turn.angle, 90) < MAXIMAL_ALLOWED_NO_TURN_DEVIATION)
+ {
+ // Keep left perfect, shift right
+ left.turn.instruction = {left_type, DirectionModifier::Right};
+ right.turn.instruction = {right_type, DirectionModifier::SharpRight};
+ return;
+ }
+ if (angularDeviation(right.turn.angle, 90) < MAXIMAL_ALLOWED_NO_TURN_DEVIATION)
+ {
+ // Keep Right perfect, shift left
+ left.turn.instruction = {left_type, DirectionModifier::SlightRight};
+ right.turn.instruction = {right_type, DirectionModifier::Right};
+ return;
+ }
+ // Two Right Turns
+ if (angularDeviation(left.turn.angle, 270) < MAXIMAL_ALLOWED_NO_TURN_DEVIATION)
+ {
+ // Keep left perfect, shift right
+ left.turn.instruction = {left_type, DirectionModifier::Left};
+ right.turn.instruction = {right_type, DirectionModifier::SlightLeft};
+ return;
+ }
+ if (angularDeviation(right.turn.angle, 270) < MAXIMAL_ALLOWED_NO_TURN_DEVIATION)
+ {
+ // Keep Right perfect, shift left
+ left.turn.instruction = {left_type, DirectionModifier::SharpLeft};
+ right.turn.instruction = {right_type, DirectionModifier::Left};
+ return;
+ }
+ // Both turns?
+ if (TurnType::Ramp != left_type && TurnType::Ramp != right_type)
+ {
+ if (left.turn.angle < STRAIGHT_ANGLE)
+ {
+ left.turn.instruction = {TurnType::FirstTurn, getTurnDirection(left.turn.angle)};
+ right.turn.instruction = {TurnType::SecondTurn, getTurnDirection(right.turn.angle)};
+ }
+ else
+ {
+ left.turn.instruction = {TurnType::SecondTurn, getTurnDirection(left.turn.angle)};
+ right.turn.instruction = {TurnType::FirstTurn, getTurnDirection(right.turn.angle)};
+ }
+ return;
+ }
+ // Shift the lesser penalty
+ if (getTurnDirection(left.turn.angle) == DirectionModifier::SharpLeft)
+ {
+ left.turn.instruction = {left_type, DirectionModifier::SharpLeft};
+ right.turn.instruction = {right_type, DirectionModifier::Left};
+ return;
+ }
+ if (getTurnDirection(right.turn.angle) == DirectionModifier::SharpRight)
+ {
+ left.turn.instruction = {left_type, DirectionModifier::Right};
+ right.turn.instruction = {right_type, DirectionModifier::SharpRight};
+ return;
+ }
+
+ if (getTurnDirection(left.turn.angle) == DirectionModifier::Right)
+ {
+ if (angularDeviation(left.turn.angle, 90) > angularDeviation(right.turn.angle, 90))
+ {
+ left.turn.instruction = {left_type, DirectionModifier::SlightRight};
+ right.turn.instruction = {right_type, DirectionModifier::Right};
+ }
+ else
+ {
+ left.turn.instruction = {left_type, DirectionModifier::Right};
+ right.turn.instruction = {right_type, DirectionModifier::SharpRight};
+ }
+ }
+ else
+ {
+ if (angularDeviation(left.turn.angle, 270) > angularDeviation(right.turn.angle, 270))
+ {
+ left.turn.instruction = {left_type, DirectionModifier::SharpLeft};
+ right.turn.instruction = {right_type, DirectionModifier::Left};
+ }
+ else
+ {
+ left.turn.instruction = {left_type, DirectionModifier::Left};
+ right.turn.instruction = {right_type, DirectionModifier::SlightLeft};
+ }
+ }
+}
+
+} // namespace guidance
+} // namespace extractor
+} // namespace osrm
diff --git a/src/extractor/restriction_parser.cpp b/src/extractor/restriction_parser.cpp
index b56af20..66cd259 100644
--- a/src/extractor/restriction_parser.cpp
+++ b/src/extractor/restriction_parser.cpp
@@ -188,7 +188,7 @@ bool RestrictionParser::ShouldIgnoreRestriction(const std::string &except_tag_st
// should this restriction be ignored? yes if there's an overlap between:
// a) the list of modes in the except tag of the restriction
// (except_tag_string), eg: except=bus;bicycle
- // b) the lua profile defines a hierachy of modes,
+ // b) the lua profile defines a hierarchy of modes,
// eg: [access, vehicle, bicycle]
if (except_tag_string.empty())
diff --git a/src/extractor/scripting_environment.cpp b/src/extractor/scripting_environment.cpp
index 53cc8e1..e3f9b6e 100644
--- a/src/extractor/scripting_environment.cpp
+++ b/src/extractor/scripting_environment.cpp
@@ -101,7 +101,7 @@ void ScriptingEnvironment::InitContext(ScriptingEnvironment::Context &context)
.property("u_turn_penalty", &ProfileProperties::GetUturnPenalty,
&ProfileProperties::SetUturnPenalty)
.def_readwrite("use_turn_restrictions", &ProfileProperties::use_turn_restrictions)
- .def_readwrite("allow_u_turn_at_via", &ProfileProperties::allow_u_turn_at_via),
+ .def_readwrite("continue_straight_at_waypoint", &ProfileProperties::continue_straight_at_waypoint),
luabind::class_<std::vector<std::string>>("vector")
.def("Add", static_cast<void (std::vector<std::string>::*)(const std::string &)>(
diff --git a/src/server/api/parameters_parser.cpp b/src/server/api/parameters_parser.cpp
index 1cf3050..1d4485a 100644
--- a/src/server/api/parameters_parser.cpp
+++ b/src/server/api/parameters_parser.cpp
@@ -1,11 +1,13 @@
#include "server/api/parameters_parser.hpp"
+#include "server/api/match_parameter_grammar.hpp"
+#include "server/api/nearest_parameter_grammar.hpp"
#include "server/api/route_parameters_grammar.hpp"
#include "server/api/table_parameter_grammar.hpp"
-#include "server/api/nearest_parameter_grammar.hpp"
-#include "server/api/trip_parameter_grammar.hpp"
-#include "server/api/match_parameter_grammar.hpp"
#include "server/api/tile_parameter_grammar.hpp"
+#include "server/api/trip_parameter_grammar.hpp"
+
+#include <type_traits>
namespace osrm
{
@@ -25,36 +27,49 @@ template <typename ParameterT,
typename GrammarT,
typename std::enable_if<detail::is_parameter_t<ParameterT>::value, int>::type = 0,
typename std::enable_if<detail::is_grammar_t<GrammarT>::value, int>::type = 0>
-boost::optional<ParameterT> parseParameters(std::string::iterator &iter, std::string::iterator end)
+boost::optional<ParameterT> parseParameters(std::string::iterator &iter,
+ const std::string::iterator end)
{
+ using It = std::decay<decltype(iter)>::type;
+
GrammarT grammar;
- const auto result = boost::spirit::qi::parse(iter, end, grammar);
- boost::optional<ParameterT> parameters;
- if (result && iter == end)
- parameters = std::move(grammar.parameters);
+ try
+ {
+ const auto ok = boost::spirit::qi::parse(iter, end, grammar);
+
+ // return move(a.b) is needed to move b out of a and then return the rvalue by implicit move
+ if (ok && iter == end)
+ return std::move(grammar.parameters);
+ }
+ catch (const qi::expectation_failure<It> &failure)
+ {
+ // The grammar above using expectation parsers ">" does not automatically increment the
+ // iterator to the failing position. Extract the position from the exception ourselves.
+ iter = failure.first;
+ }
- return parameters;
+ return boost::none;
}
} // ns detail
template <>
boost::optional<engine::api::RouteParameters> parseParameters(std::string::iterator &iter,
- std::string::iterator end)
+ const std::string::iterator end)
{
return detail::parseParameters<engine::api::RouteParameters, RouteParametersGrammar>(iter, end);
}
template <>
boost::optional<engine::api::TableParameters> parseParameters(std::string::iterator &iter,
- std::string::iterator end)
+ const std::string::iterator end)
{
return detail::parseParameters<engine::api::TableParameters, TableParametersGrammar>(iter, end);
}
template <>
boost::optional<engine::api::NearestParameters> parseParameters(std::string::iterator &iter,
- std::string::iterator end)
+ const std::string::iterator end)
{
return detail::parseParameters<engine::api::NearestParameters, NearestParametersGrammar>(iter,
end);
@@ -62,21 +77,21 @@ boost::optional<engine::api::NearestParameters> parseParameters(std::string::ite
template <>
boost::optional<engine::api::TripParameters> parseParameters(std::string::iterator &iter,
- std::string::iterator end)
+ const std::string::iterator end)
{
return detail::parseParameters<engine::api::TripParameters, TripParametersGrammar>(iter, end);
}
template <>
boost::optional<engine::api::MatchParameters> parseParameters(std::string::iterator &iter,
- std::string::iterator end)
+ const std::string::iterator end)
{
return detail::parseParameters<engine::api::MatchParameters, MatchParametersGrammar>(iter, end);
}
template <>
boost::optional<engine::api::TileParameters> parseParameters(std::string::iterator &iter,
- std::string::iterator end)
+ const std::string::iterator end)
{
return detail::parseParameters<engine::api::TileParameters, TileParametersGrammar>(iter, end);
}
diff --git a/src/server/api/url_parser.cpp b/src/server/api/url_parser.cpp
index 661b1f6..7ef6db0 100644
--- a/src/server/api/url_parser.cpp
+++ b/src/server/api/url_parser.cpp
@@ -1,88 +1,86 @@
#include "server/api/url_parser.hpp"
-
#include "engine/polyline_compressor.hpp"
-#include <boost/bind.hpp>
-#include <boost/spirit/include/qi_char_.hpp>
-#include <boost/spirit/include/qi_grammar.hpp>
-#include <boost/spirit/include/qi_uint.hpp>
-#include <boost/spirit/include/qi_real.hpp>
-#include <boost/spirit/include/qi_lit.hpp>
-#include <boost/spirit/include/qi_action.hpp>
-#include <boost/spirit/include/qi_as_string.hpp>
-#include <boost/spirit/include/qi_operator.hpp>
-#include <boost/spirit/include/qi_plus.hpp>
+//#define BOOST_SPIRIT_DEBUG
+#include <boost/spirit/include/qi.hpp>
-namespace osrm
-{
-namespace server
-{
-namespace api
-{
+#include <string>
+#include <type_traits>
+// Keep impl. TU local
namespace
{
-
namespace qi = boost::spirit::qi;
-using Iterator = std::string::iterator;
-struct URLGrammar : boost::spirit::qi::grammar<Iterator>
+
+template <typename Iterator, typename Into> //
+struct URLParser final : qi::grammar<Iterator, Into>
{
- URLGrammar() : URLGrammar::base_type(url_rule)
+ URLParser() : URLParser::base_type(start)
{
- const auto set_service = [this](std::string &service)
- {
- parsed_url.service = std::move(service);
- };
- const auto set_version = [this](const unsigned version)
- {
- parsed_url.version = version;
- };
- const auto set_profile = [this](std::string &profile)
- {
- parsed_url.profile = std::move(profile);
- };
- const auto set_query = [this](std::string &query)
- {
- parsed_url.query = std::move(query);
- };
-
alpha_numeral = qi::char_("a-zA-Z0-9");
polyline_chars = qi::char_("a-zA-Z0-9_.--[]{}@?|\\%~`^");
all_chars = polyline_chars | qi::char_("=,;:&().");
- service_rule = +alpha_numeral;
- version_rule = qi::uint_;
- profile_rule = +alpha_numeral;
- query_rule = +all_chars;
+ service = +alpha_numeral;
+ version = qi::uint_;
+ profile = +alpha_numeral;
+ query = +all_chars;
+
+ // Example input: /route/v1/driving/7.416351,43.731205;7.420363,43.736189
+
+ start = qi::lit('/') > service //
+ > qi::lit('/') > qi::lit('v') > version //
+ > qi::lit('/') > profile //
+ > qi::lit('/') > query; //
- url_rule = qi::lit('/') >> service_rule[set_service] >> qi::lit('/') >> qi::lit('v') >>
- version_rule[set_version] >> qi::lit('/') >> profile_rule[set_profile] >>
- qi::lit('/') >> query_rule[set_query];
+ BOOST_SPIRIT_DEBUG_NODES((start)(service)(version)(profile)(query))
}
- ParsedURL parsed_url;
+ qi::rule<Iterator, Into> start;
- qi::rule<Iterator> url_rule;
- qi::rule<Iterator, std::string()> service_rule, profile_rule, query_rule;
- qi::rule<Iterator, unsigned()> version_rule;
- qi::rule<Iterator, char()> alpha_numeral, all_chars, polyline_chars;
+ qi::rule<Iterator, std::string()> service;
+ qi::rule<Iterator, unsigned()> version;
+ qi::rule<Iterator, std::string()> profile;
+ qi::rule<Iterator, std::string()> query;
+
+ qi::rule<Iterator, char()> alpha_numeral;
+ qi::rule<Iterator, char()> all_chars;
+ qi::rule<Iterator, char()> polyline_chars;
};
-}
-boost::optional<ParsedURL> parseURL(std::string::iterator &iter, std::string::iterator end)
+} // anon.
+
+namespace osrm
+{
+namespace server
+{
+namespace api
+{
+
+boost::optional<ParsedURL> parseURL(std::string::iterator &iter, const std::string::iterator end)
{
- boost::optional<ParsedURL> parsed_url;
+ using It = std::decay<decltype(iter)>::type;
- URLGrammar grammar;
- const auto result = boost::spirit::qi::parse(iter, end, grammar);
+ static URLParser<It, ParsedURL()> const parser;
+ ParsedURL out;
- if (result && iter == end)
+ try
{
- parsed_url = std::move(grammar.parsed_url);
+ const auto ok = boost::spirit::qi::parse(iter, end, parser, out);
+
+ if (ok && iter == end)
+ return boost::make_optional(out);
+ }
+ catch (const qi::expectation_failure<It> &failure)
+ {
+ // The grammar above using expectation parsers ">" does not automatically increment the
+ // iterator to the failing position. Extract the position from the exception ourselves.
+ iter = failure.first;
}
- return parsed_url;
-}
-}
-}
+ return boost::none;
}
+
+} // api
+} // server
+} // osrm
diff --git a/src/server/connection.cpp b/src/server/connection.cpp
index e7725fb..0fa31e6 100644
--- a/src/server/connection.cpp
+++ b/src/server/connection.cpp
@@ -7,6 +7,7 @@
#include <boost/iostreams/filtering_stream.hpp>
#include <boost/iostreams/filter/gzip.hpp>
+#include <iterator>
#include <string>
#include <vector>
diff --git a/src/server/request_handler.cpp b/src/server/request_handler.cpp
index 888a92b..cfe74f2 100644
--- a/src/server/request_handler.cpp
+++ b/src/server/request_handler.cpp
@@ -21,6 +21,7 @@
#include <ctime>
#include <algorithm>
+#include <iterator>
#include <iostream>
#include <string>
@@ -77,7 +78,6 @@ void RequestHandler::HandleRequest(const http::request ¤t_request, http::r
auto api_iterator = request_string.begin();
auto maybe_parsed_url = api::parseURL(api_iterator, request_string.end());
- ;
ServiceHandler::ResultT result;
// check if the was an error with the request
@@ -85,7 +85,7 @@ void RequestHandler::HandleRequest(const http::request ¤t_request, http::r
{
const engine::Status status =
- service_handler->RunQuery(std::move(*maybe_parsed_url), result);
+ service_handler->RunQuery(*std::move(maybe_parsed_url), result);
if (status != engine::Status::Ok)
{
// 4xx bad request return code
@@ -103,7 +103,7 @@ void RequestHandler::HandleRequest(const http::request ¤t_request, http::r
const auto context_begin = request_string.begin() + ((position < 3) ? 0 : (position - 3UL));
BOOST_ASSERT(context_begin >= request_string.begin());
const auto context_end =
- request_string.begin() + std::min(position + 3UL, request_string.size());
+ request_string.begin() + std::min<std::size_t>(position + 3UL, request_string.size());
BOOST_ASSERT(context_end <= request_string.end());
std::string context(context_begin, context_end);
diff --git a/src/storage/storage.cpp b/src/storage/storage.cpp
index 862ca3c..67fd122 100644
--- a/src/storage/storage.cpp
+++ b/src/storage/storage.cpp
@@ -30,6 +30,7 @@
#include <cstdint>
#include <fstream>
+#include <iterator>
#include <new>
#include <string>
diff --git a/src/tools/contract.cpp b/src/tools/contract.cpp
index 5bc65c5..c9460db 100644
--- a/src/tools/contract.cpp
+++ b/src/tools/contract.cpp
@@ -61,8 +61,9 @@ return_code parseArguments(int argc, char *argv[], contractor::ContractorConfig
boost::program_options::options_description cmdline_options;
cmdline_options.add(generic_options).add(config_options).add(hidden_options);
+ const auto* executable = argv[0];
boost::program_options::options_description visible_options(
- "Usage: " + boost::filesystem::basename(argv[0]) + " <input.osrm> [options]");
+ "Usage: " + boost::filesystem::path(executable).filename().string() + " <input.osrm> [options]");
visible_options.add(generic_options).add(config_options);
// parse command line options
diff --git a/src/tools/extract.cpp b/src/tools/extract.cpp
index 4c5fa4c..672ada2 100644
--- a/src/tools/extract.cpp
+++ b/src/tools/extract.cpp
@@ -64,8 +64,9 @@ return_code parseArguments(int argc, char *argv[], extractor::ExtractorConfig &e
boost::program_options::options_description cmdline_options;
cmdline_options.add(generic_options).add(config_options).add(hidden_options);
+ const auto* executable = argv[0];
boost::program_options::options_description visible_options(
- boost::filesystem::basename(argv[0]) + " <input.osm/.osm.bz2/.osm.pbf> [options]");
+ boost::filesystem::path(executable).filename().string() + " <input.osm/.osm.bz2/.osm.pbf> [options]");
visible_options.add(generic_options).add(config_options);
// parse command line options
diff --git a/src/tools/routed.cpp b/src/tools/routed.cpp
index 6c49d4e..831a9cd 100644
--- a/src/tools/routed.cpp
+++ b/src/tools/routed.cpp
@@ -109,8 +109,9 @@ generateServerProgramOptions(const int argc,
boost::program_options::options_description cmdline_options;
cmdline_options.add(generic_options).add(config_options).add(hidden_options);
+ const auto* executable = argv[0];
boost::program_options::options_description visible_options(
- boost::filesystem::path(argv[0]).stem().string() + " <base.osrm> [<options>]");
+ boost::filesystem::path(executable).filename().string() + " <base.osrm> [<options>]");
visible_options.add(generic_options).add(config_options);
// parse command line options
diff --git a/src/tools/store.cpp b/src/tools/store.cpp
index 7866cf3..9e7cbbc 100644
--- a/src/tools/store.cpp
+++ b/src/tools/store.cpp
@@ -35,8 +35,9 @@ bool generateDataStoreOptions(const int argc, const char *argv[], boost::filesys
boost::program_options::options_description cmdline_options;
cmdline_options.add(generic_options).add(config_options).add(hidden_options);
+ const auto* executable = argv[0];
boost::program_options::options_description visible_options(
- boost::filesystem::basename(argv[0]) + " [<options>] <configuration>");
+ boost::filesystem::path(executable).filename().string() + " [<options>] <configuration>");
visible_options.add(generic_options).add(config_options);
// print help options if no infile is specified
diff --git a/src/util/coordinate_calculation.cpp b/src/util/coordinate_calculation.cpp
index 8ed69c9..24b280f 100644
--- a/src/util/coordinate_calculation.cpp
+++ b/src/util/coordinate_calculation.cpp
@@ -1,6 +1,7 @@
#include "util/coordinate.hpp"
#include "util/coordinate_calculation.hpp"
#include "util/trigonometry_table.hpp"
+#include "util/web_mercator.hpp"
#include <boost/assert.hpp>
@@ -18,10 +19,10 @@ namespace coordinate_calculation
{
// Does not project the coordinates!
-double squaredEuclideanDistance(const FloatCoordinate &lhs, const FloatCoordinate &rhs)
+std::uint64_t squaredEuclideanDistance(const Coordinate &lhs, const Coordinate &rhs)
{
- const double dx = static_cast<double>(lhs.lon - rhs.lon);
- const double dy = static_cast<double>(lhs.lat - rhs.lat);
+ const std::uint64_t dx = static_cast<std::int32_t>(lhs.lon - rhs.lon);
+ const std::uint64_t dy = static_cast<std::int32_t>(lhs.lat - rhs.lat);
return dx * dx + dy * dy;
}
@@ -40,11 +41,11 @@ double haversineDistance(const Coordinate coordinate_1, const Coordinate coordin
const double ln1 = lon1 / COORDINATE_PRECISION;
const double lt2 = lat2 / COORDINATE_PRECISION;
const double ln2 = lon2 / COORDINATE_PRECISION;
- const double dlat1 = lt1 * DEGREE_TO_RAD;
+ const double dlat1 = lt1 * detail::DEGREE_TO_RAD;
- const double dlong1 = ln1 * DEGREE_TO_RAD;
- const double dlat2 = lt2 * DEGREE_TO_RAD;
- const double dlong2 = ln2 * DEGREE_TO_RAD;
+ const double dlong1 = ln1 * detail::DEGREE_TO_RAD;
+ const double dlat2 = lt2 * detail::DEGREE_TO_RAD;
+ const double dlong2 = ln2 * detail::DEGREE_TO_RAD;
const double dlong = dlong1 - dlong2;
const double dlat = dlat1 - dlat2;
@@ -52,7 +53,7 @@ double haversineDistance(const Coordinate coordinate_1, const Coordinate coordin
const double aharv = std::pow(std::sin(dlat / 2.0), 2.0) +
std::cos(dlat1) * std::cos(dlat2) * std::pow(std::sin(dlong / 2.), 2);
const double charv = 2. * std::atan2(std::sqrt(aharv), std::sqrt(1.0 - aharv));
- return EARTH_RADIUS * charv;
+ return detail::EARTH_RADIUS * charv;
}
double greatCircleDistance(const Coordinate coordinate_1, const Coordinate coordinate_2)
@@ -66,14 +67,14 @@ double greatCircleDistance(const Coordinate coordinate_1, const Coordinate coord
BOOST_ASSERT(lat2 != std::numeric_limits<int>::min());
BOOST_ASSERT(lon2 != std::numeric_limits<int>::min());
- const double float_lat1 = (lat1 / COORDINATE_PRECISION) * DEGREE_TO_RAD;
- const double float_lon1 = (lon1 / COORDINATE_PRECISION) * DEGREE_TO_RAD;
- const double float_lat2 = (lat2 / COORDINATE_PRECISION) * DEGREE_TO_RAD;
- const double float_lon2 = (lon2 / COORDINATE_PRECISION) * DEGREE_TO_RAD;
+ const double float_lat1 = (lat1 / COORDINATE_PRECISION) * detail::DEGREE_TO_RAD;
+ const double float_lon1 = (lon1 / COORDINATE_PRECISION) * detail::DEGREE_TO_RAD;
+ const double float_lat2 = (lat2 / COORDINATE_PRECISION) * detail::DEGREE_TO_RAD;
+ const double float_lon2 = (lon2 / COORDINATE_PRECISION) * detail::DEGREE_TO_RAD;
const double x_value = (float_lon2 - float_lon1) * std::cos((float_lat1 + float_lat2) / 2.0);
const double y_value = float_lat2 - float_lat1;
- return std::hypot(x_value, y_value) * EARTH_RADIUS;
+ return std::hypot(x_value, y_value) * detail::EARTH_RADIUS;
}
std::pair<double, FloatCoordinate> projectPointOnSegment(const FloatCoordinate &source,
@@ -104,10 +105,13 @@ std::pair<double, FloatCoordinate> projectPointOnSegment(const FloatCoordinate &
{
clamped_ratio = 0.;
}
+
return {clamped_ratio,
{
- source.lon + slope_vector.lon * FloatLongitude(clamped_ratio),
- source.lat + slope_vector.lat * FloatLatitude(clamped_ratio),
+ FloatLongitude(1.0 - clamped_ratio) * source.lon +
+ target.lon * FloatLongitude(clamped_ratio),
+ FloatLatitude(1.0 - clamped_ratio) * source.lat +
+ target.lat * FloatLatitude(clamped_ratio),
}};
}
@@ -122,9 +126,10 @@ double perpendicularDistance(const Coordinate segment_source,
BOOST_ASSERT(query_location.IsValid());
FloatCoordinate projected_nearest;
- std::tie(ratio, projected_nearest) =
- projectPointOnSegment(mercator::fromWGS84(segment_source), mercator::fromWGS84(segment_target), mercator::fromWGS84(query_location));
- nearest_location = mercator::toWGS84(projected_nearest);
+ std::tie(ratio, projected_nearest) = projectPointOnSegment(
+ web_mercator::fromWGS84(segment_source), web_mercator::fromWGS84(segment_target),
+ web_mercator::fromWGS84(query_location));
+ nearest_location = web_mercator::toWGS84(projected_nearest);
const double approximate_distance = greatCircleDistance(query_location, nearest_location);
BOOST_ASSERT(0.0 <= approximate_distance);
@@ -192,12 +197,19 @@ double computeAngle(const Coordinate first, const Coordinate second, const Coord
using namespace boost::math::constants;
using namespace coordinate_calculation;
+ if (first == second || second == third)
+ return 180;
+
+ BOOST_ASSERT(first.IsValid());
+ BOOST_ASSERT(second.IsValid());
+ BOOST_ASSERT(third.IsValid());
+
const double v1x = static_cast<double>(toFloating(first.lon - second.lon));
const double v1y =
- mercator::latToY(toFloating(first.lat)) - mercator::latToY(toFloating(second.lat));
+ web_mercator::latToY(toFloating(first.lat)) - web_mercator::latToY(toFloating(second.lat));
const double v2x = static_cast<double>(toFloating(third.lon - second.lon));
const double v2y =
- mercator::latToY(toFloating(third.lat)) - mercator::latToY(toFloating(second.lat));
+ web_mercator::latToY(toFloating(third.lat)) - web_mercator::latToY(toFloating(second.lat));
double angle = (atan2_lookup(v2y, v2x) - atan2_lookup(v1y, v1x)) * 180. / pi<double>();
@@ -206,120 +218,109 @@ double computeAngle(const Coordinate first, const Coordinate second, const Coord
angle += 360.;
}
+ BOOST_ASSERT(angle >= 0);
return angle;
}
-Coordinate interpolateLinear(double factor, const Coordinate from, const Coordinate to)
-{
- BOOST_ASSERT(0 <= factor && factor <= 1.0);
-
- FixedLongitude interpolated_lon(((1. - factor) * static_cast<std::int32_t>(from.lon)) +
- (factor * static_cast<std::int32_t>(to.lon)));
- FixedLatitude interpolated_lat(((1. - factor) * static_cast<std::int32_t>(from.lat)) +
- (factor * static_cast<std::int32_t>(to.lat)));
-
- return {std::move(interpolated_lon), std::move(interpolated_lat)};
-}
-
-namespace mercator
-{
-FloatLatitude yToLat(const double y)
-{
- const auto clamped_y = std::max(-180., std::min(180., y));
- const double normalized_lat =
- RAD_TO_DEGREE * 2. * std::atan(std::exp(clamped_y * DEGREE_TO_RAD));
-
- return FloatLatitude(normalized_lat - 90.);
-}
-
-double latToY(const FloatLatitude latitude)
-{
- const double normalized_lat = 90. + static_cast<double>(latitude);
-
- const double y = RAD_TO_DEGREE * std::log(std::tan(normalized_lat * DEGREE_TO_RAD * 0.5));
- const auto clamped_y = std::max(-180., std::min(180., y));
- return clamped_y;
-}
-
-FloatLatitude clamp(const FloatLatitude lat)
-{
- return std::max(std::min(lat, FloatLatitude(detail::MAX_LATITUDE)),
- FloatLatitude(-detail::MAX_LATITUDE));
-}
-
-FloatLongitude clamp(const FloatLongitude lon)
-{
- return std::max(std::min(lon, FloatLongitude(detail::MAX_LONGITUDE)),
- FloatLongitude(-detail::MAX_LONGITUDE));
-}
-
-inline void pixelToDegree(const double shift, double &x, double &y)
-{
- const double b = shift / 2.0;
- x = (x - b) / shift * 360.0;
- // FIXME needs to be simplified
- const double g = (y - b) / -(shift / (2 * M_PI)) / DEGREE_TO_RAD;
- static_assert(DEGREE_TO_RAD / (2 * M_PI) - 1 / 360. < 0.0001, "");
- y = static_cast<double>(util::coordinate_calculation::mercator::yToLat(g));
-}
-
-double degreeToPixel(FloatLongitude lon, unsigned zoom)
+boost::optional<Coordinate>
+circleCenter(const Coordinate C1, const Coordinate C2, const Coordinate C3)
{
- const double shift = (1u << zoom) * TILE_SIZE;
- const double b = shift / 2.0;
- const double x = b * (1 + static_cast<double>(lon) / 180.0);
- return x;
-}
-
-double degreeToPixel(FloatLatitude lat, unsigned zoom)
-{
- const double shift = (1u << zoom) * TILE_SIZE;
- const double b = shift / 2.0;
- const double y = b * (1. - latToY(lat) / 180.);
- return y;
-}
-
-FloatCoordinate fromWGS84(const FloatCoordinate &wgs84_coordinate)
-{
- return {wgs84_coordinate.lon, FloatLatitude{coordinate_calculation::mercator::latToY(wgs84_coordinate.lat)}};
-}
+ // free after http://paulbourke.net/geometry/circlesphere/
+ // require three distinct points
+ if (C1 == C2 || C2 == C3 || C1 == C3)
+ {
+ return boost::none;
+ }
-FloatCoordinate toWGS84(const FloatCoordinate &mercator_coordinate)
-{
- return {mercator_coordinate.lon, coordinate_calculation::mercator::yToLat(static_cast<double>(mercator_coordinate.lat))};
+ // define line through c1, c2 and c2,c3
+ const double C2C1_lat = static_cast<double>(toFloating(C2.lat - C1.lat)); // yDelta_a
+ const double C2C1_lon = static_cast<double>(toFloating(C2.lon - C1.lon)); // xDelta_a
+ const double C3C2_lat = static_cast<double>(toFloating(C3.lat - C2.lat)); // yDelta_b
+ const double C3C2_lon = static_cast<double>(toFloating(C3.lon - C2.lon)); // xDelta_b
+
+ // check for collinear points in X-Direction / Y-Direction
+ if ((std::abs(C2C1_lon) < std::numeric_limits<double>::epsilon() &&
+ std::abs(C3C2_lon) < std::numeric_limits<double>::epsilon()) ||
+ (std::abs(C2C1_lat) < std::numeric_limits<double>::epsilon() &&
+ std::abs(C3C2_lat) < std::numeric_limits<double>::epsilon()))
+ {
+ return boost::none;
+ }
+ else if (std::abs(C2C1_lon) < std::numeric_limits<double>::epsilon())
+ {
+ // vertical line C2C1
+ // due to c1.lon == c2.lon && c1.lon != c3.lon we can rearrange this way
+ BOOST_ASSERT(std::abs(static_cast<double>(toFloating(C3.lon - C1.lon))) >=
+ std::numeric_limits<double>::epsilon() &&
+ std::abs(static_cast<double>(toFloating(C2.lon - C3.lon))) >=
+ std::numeric_limits<double>::epsilon());
+ return circleCenter(C1, C3, C2);
+ }
+ else if (std::abs(C3C2_lon) < std::numeric_limits<double>::epsilon())
+ {
+ // vertical line C3C2
+ // due to c2.lon == c3.lon && c1.lon != c3.lon we can rearrange this way
+ // after rearrangement both deltas will be zero
+ BOOST_ASSERT(std::abs(static_cast<double>(toFloating(C1.lon - C2.lon))) >=
+ std::numeric_limits<double>::epsilon() &&
+ std::abs(static_cast<double>(toFloating(C3.lon - C1.lon))) >=
+ std::numeric_limits<double>::epsilon());
+ return circleCenter(C2, C1, C3);
+ }
+ else
+ {
+ const double C2C1_slope = C2C1_lat / C2C1_lon;
+ const double C3C2_slope = C3C2_lat / C3C2_lon;
+
+ if (std::abs(C2C1_slope) < std::numeric_limits<double>::epsilon())
+ {
+ // Three non-collinear points with C2,C1 on same latitude.
+ // Due to the x-values correct, we can swap C3 and C1 to obtain the correct slope value
+ return circleCenter(C3, C2, C1);
+ }
+ // valid slope values for both lines, calculate the center as intersection of the lines
+
+ // can this ever happen?
+ if (std::abs(C2C1_slope - C3C2_slope) < std::numeric_limits<double>::epsilon())
+ return boost::none;
+
+ const double C1_y = static_cast<double>(toFloating(C1.lat));
+ const double C1_x = static_cast<double>(toFloating(C1.lon));
+ const double C2_y = static_cast<double>(toFloating(C2.lat));
+ const double C2_x = static_cast<double>(toFloating(C2.lon));
+ const double C3_y = static_cast<double>(toFloating(C3.lat));
+ const double C3_x = static_cast<double>(toFloating(C3.lon));
+
+ const double lon = (C2C1_slope * C3C2_slope * (C1_y - C3_y) + C3C2_slope * (C1_x + C2_x) -
+ C2C1_slope * (C2_x + C3_x)) /
+ (2 * (C3C2_slope - C2C1_slope));
+ const double lat = (0.5 * (C1_x + C2_x) - lon) / C2C1_slope + 0.5 * (C1_y + C2_y);
+ return Coordinate(FloatLongitude(lon), FloatLatitude(lat));
+ }
}
-// Converts a WMS tile coordinate (z,x,y) into a wgs bounding box
-void xyzToWGS84(
- const int x, const int y, const int z, double &minx, double &miny, double &maxx, double &maxy)
+double circleRadius(const Coordinate C1, const Coordinate C2, const Coordinate C3)
{
- using util::coordinate_calculation::mercator::TILE_SIZE;
-
- minx = x * TILE_SIZE;
- miny = (y + 1.0) * TILE_SIZE;
- maxx = (x + 1.0) * TILE_SIZE;
- maxy = y * TILE_SIZE;
- // 2^z * TILE_SIZE
- const double shift = (1u << static_cast<unsigned>(z)) * TILE_SIZE;
- pixelToDegree(shift, minx, miny);
- pixelToDegree(shift, maxx, maxy);
+ // a circle by three points requires thee distinct points
+ auto center = circleCenter(C1, C2, C3);
+ if (center)
+ return haversineDistance(C1, *center);
+ else
+ return std::numeric_limits<double>::infinity();
}
-// Converts a WMS tile coordinate (z,x,y) into a mercator bounding box
-void xyzToMercator(
- const int x, const int y, const int z, double &minx, double &miny, double &maxx, double &maxy)
+Coordinate interpolateLinear(double factor, const Coordinate from, const Coordinate to)
{
- using namespace util::coordinate_calculation::mercator;
+ BOOST_ASSERT(0 <= factor && factor <= 1.0);
- xyzToWGS84(x, y, z, minx, miny, maxx, maxy);
+ FixedLongitude interpolated_lon(((1. - factor) * static_cast<std::int32_t>(from.lon)) +
+ (factor * static_cast<std::int32_t>(to.lon)));
+ FixedLatitude interpolated_lat(((1. - factor) * static_cast<std::int32_t>(from.lat)) +
+ (factor * static_cast<std::int32_t>(to.lat)));
- minx = static_cast<double>(clamp(util::FloatLongitude(minx))) * DEGREE_TO_PX;
- miny = latToY(clamp(util::FloatLatitude(miny))) * DEGREE_TO_PX;
- maxx = static_cast<double>(clamp(util::FloatLongitude(maxx))) * DEGREE_TO_PX;
- maxy = latToY(clamp(util::FloatLatitude(maxy))) * DEGREE_TO_PX;
+ return {std::move(interpolated_lon), std::move(interpolated_lat)};
}
-} // ns mercato // ns mercatorr
} // ns coordinate_calculation
} // ns util
} // ns osrm
diff --git a/src/util/name_table.cpp b/src/util/name_table.cpp
index e3d5cef..fedc31f 100644
--- a/src/util/name_table.cpp
+++ b/src/util/name_table.cpp
@@ -1,10 +1,10 @@
+#include "util/exception.hpp"
#include "util/name_table.hpp"
#include "util/simple_logger.hpp"
-#include "util/exception.hpp"
#include <algorithm>
-#include <limits>
#include <fstream>
+#include <limits>
#include <boost/filesystem/fstream.hpp>
@@ -17,27 +17,30 @@ NameTable::NameTable(const std::string &filename)
{
boost::filesystem::ifstream name_stream(filename, std::ios::binary);
- if( !name_stream )
+ if (!name_stream)
throw exception("Failed to open " + filename + " for reading.");
name_stream >> m_name_table;
unsigned number_of_chars = 0;
name_stream.read(reinterpret_cast<char *>(&number_of_chars), sizeof(number_of_chars));
- if( !name_stream )
+ if (!name_stream)
throw exception("Encountered invalid file, failed to read number of contained chars");
- BOOST_ASSERT_MSG(0 != number_of_chars, "name file broken");
m_names_char_list.resize(number_of_chars + 1); //+1 gives sentinel element
- name_stream.read(reinterpret_cast<char *>(&m_names_char_list[0]),
- number_of_chars * sizeof(m_names_char_list[0]));
- if( !name_stream )
- throw exception("Failed to read " + std::to_string(number_of_chars) + " characters from file.");
-
- if (0 == m_names_char_list.size())
+ m_names_char_list.back() = 0;
+ if (number_of_chars > 0)
+ {
+ name_stream.read(reinterpret_cast<char *>(&m_names_char_list[0]),
+ number_of_chars * sizeof(m_names_char_list[0]));
+ }
+ else
{
util::SimpleLogger().Write(logWARNING) << "list of street names is empty";
}
+ if (!name_stream)
+ throw exception("Failed to read " + std::to_string(number_of_chars) +
+ " characters from file.");
}
std::string NameTable::GetNameForID(const unsigned name_id) const
diff --git a/taginfo.json b/taginfo.json
index 4ef48de..8acc7d7 100644
--- a/taginfo.json
+++ b/taginfo.json
@@ -77,6 +77,7 @@
{"key": "access", "value": "emergency"},
{"key": "access", "value": "psv"},
{"key": "access", "value": "delivery"},
+ {"key": "maxspeed", "value": "none"},
{"key": "maxspeed", "value": "urban"},
{"key": "maxspeed", "value": "rural"},
{"key": "maxspeed", "value": "trunk"},
diff --git a/test/data/Makefile b/test/data/Makefile
index 0ddda31..8684bc8 100755
--- a/test/data/Makefile
+++ b/test/data/Makefile
@@ -1,29 +1,54 @@
-MONACO_URL:=https://s3.amazonaws.com/mapbox/osrm/testing/monaco.osm.pbf
+DATA_NAME:=monaco
+DATA_URL:=https://s3.amazonaws.com/mapbox/osrm/testing/$(DATA_NAME).osm.pbf
+DATA_POLY_URL:=https://s3.amazonaws.com/mapbox/osrm/testing/$(DATA_NAME).poly
TOOL_ROOT:=../../build
PROFILE_ROOT:=../../profiles
+SCRIPT_ROOT:=../../scripts
OSRM_EXTRACT:=$(TOOL_ROOT)/osrm-extract
OSRM_CONTRACT:=$(TOOL_ROOT)/osrm-contract
+OSRM_ROUTED:=$(TOOL_ROOT)/osrm-routed
+POLY2REQ:=$(SCRIPT_ROOT)/poly2req.js
+TIMER:=$(SCRIPT_ROOT)/timer.sh
PROFILE:=$(PROFILE_ROOT)/car.lua
-all: monaco.osrm.hsgr
+all: $(DATA_NAME).osrm.hsgr
clean:
- rm monaco.*
+ rm $(DATA_NAME).*
-monaco.osm.pbf:
- wget $(MONACO_URL) -O monaco.osm.pbf
+$(DATA_NAME).osm.pbf:
+ wget $(DATA_URL) -O $(DATA_NAME).osm.pbf
-monaco.osrm: monaco.osm.pbf $(PROFILE) $(OSRM_EXTRACT)
+$(DATA_NAME).poly:
+ wget $(DATA_POLY_URL) -O $(DATA_NAME).poly
+
+$(DATA_NAME).osrm: $(DATA_NAME).osm.pbf $(DATA_NAME).poly $(PROFILE) $(OSRM_EXTRACT)
@echo "Verifiyng data file integrity..."
md5sum -c data.md5sum
@echo "Running osrm-extract..."
- $(OSRM_EXTRACT) monaco.osm.pbf -p $(PROFILE)
+ $(TIMER) "osrm-extract" $(OSRM_EXTRACT) $(DATA_NAME).osm.pbf -p $(PROFILE)
-monaco.osrm.hsgr: monaco.osrm $(PROFILE) $(OSRM_CONTRACT)
+$(DATA_NAME).osrm.hsgr: $(DATA_NAME).osrm $(PROFILE) $(OSRM_CONTRACT)
@echo "Running osrm-contract..."
- $(OSRM_CONTRACT) monaco.osrm
+ $(TIMER) "osrm-contract" $(OSRM_CONTRACT) $(DATA_NAME).osrm
+
+$(DATA_NAME).requests: $(DATA_NAME).poly
+ $(POLY2REQ) $(DATA_NAME).poly > $(DATA_NAME).requests
+
+osrm-routed.pid: $(DATA_NAME).osrm.hsgr
+ @/bin/sh -c '$(OSRM_ROUTED) $(DATA_NAME).osrm& echo "$$!" > osrm-routed.pid'
+ sleep 1
+
+benchmark: $(DATA_NAME).requests osrm-routed.pid
+ @echo "Running benchmark..."
+ $(TIMER) "queries" "cat $(DATA_NAME).requests | xargs curl &> /dev/null"
+ @cat osrm-routed.pid | xargs kill
+ @rm osrm-routed.pid
+ @echo "**** timings ***"
+ @cat /tmp/osrm.timings
+ @echo "****************"
checksum:
- md5sum monaco.osm.pbf > data.md5sum
+ md5sum $(DATA_NAME).osm.pbf $(DATA_NAME).poly > data.md5sum
-.PHONY: clean checksum
+.PHONY: clean checksum benchmark
diff --git a/test/data/data.md5sum b/test/data/data.md5sum
index 47151b4..9bcfd33 100644
--- a/test/data/data.md5sum
+++ b/test/data/data.md5sum
@@ -1 +1,2 @@
2b8dd9343d5e615afc9c67bcc7028a63 monaco.osm.pbf
+b0788991ab3791d53c1c20b6281f81ad monaco.poly
diff --git a/unit_tests/CMakeLists.txt b/unit_tests/CMakeLists.txt
new file mode 100644
index 0000000..63e10c7
--- /dev/null
+++ b/unit_tests/CMakeLists.txt
@@ -0,0 +1,76 @@
+file(GLOB EngineTestsSources
+ engine_tests.cpp
+ engine/*.cpp)
+
+file(GLOB ExtractorTestsSources
+ extractor_tests.cpp
+ extractor/*.cpp)
+
+file(GLOB LibraryTestsSources
+ library_tests.cpp
+ library/*.cpp)
+
+file(GLOB ServerTestsSources
+ server_tests.cpp
+ server/*.cpp)
+
+file(GLOB UtilTestsSources
+ util_tests.cpp
+ util/*.cpp)
+
+
+add_executable(engine-tests
+ EXCLUDE_FROM_ALL
+ ${EngineTestsSources}
+ $<TARGET_OBJECTS:ENGINE> $<TARGET_OBJECTS:STORAGE> $<TARGET_OBJECTS:UTIL>)
+
+add_executable(extractor-tests
+ EXCLUDE_FROM_ALL
+ ${ExtractorTestsSources}
+ $<TARGET_OBJECTS:EXTRACTOR> $<TARGET_OBJECTS:UTIL>)
+
+add_executable(library-tests
+ EXCLUDE_FROM_ALL
+ ${LibraryTestsSources})
+
+add_executable(server-tests
+ EXCLUDE_FROM_ALL
+ ${ServerTestsSources}
+ $<TARGET_OBJECTS:UTIL> $<TARGET_OBJECTS:SERVER>)
+
+add_executable(util-tests
+ EXCLUDE_FROM_ALL
+ ${UtilTestsSources}
+ $<TARGET_OBJECTS:UTIL>)
+
+
+# FindPackage below overwrites Boost_LIBRARIES
+set(AllBoostLibrariesExceptUnitTest ${Boost_LIBRARIES})
+
+find_package(Boost 1.49.0 REQUIRED COMPONENTS unit_test_framework)
+
+if(NOT WIN32)
+ add_definitions(-DBOOST_TEST_DYN_LINK)
+endif()
+
+# After the find_package call we got only the unit test library
+set(BoostUnitTestLibrary ${Boost_LIBRARIES})
+
+include_directories(SYSTEM ${Boost_INCLUDE_DIRS})
+
+
+target_include_directories(engine-tests PUBLIC ${CMAKE_CURRENT_SOURCE_DIR})
+target_include_directories(library-tests PUBLIC ${CMAKE_CURRENT_SOURCE_DIR})
+target_include_directories(util-tests PUBLIC ${CMAKE_CURRENT_SOURCE_DIR})
+
+
+target_link_libraries(engine-tests ${ENGINE_LIBRARIES} ${BoostUnitTestLibrary})
+target_link_libraries(extractor-tests ${EXTRACTOR_LIBRARIES} ${BoostUnitTestLibrary})
+target_link_libraries(library-tests osrm ${Boost_LIBRARIES} ${BoostUnitTestLibrary})
+target_link_libraries(server-tests osrm ${Boost_LIBRARIES} ${BoostUnitTestLibrary} ${ZLIB_LIBRARY})
+target_link_libraries(util-tests ${UTIL_LIBRARIES} ${BoostUnitTestLibrary})
+
+
+add_custom_target(tests
+ DEPENDS
+ engine-tests extractor-tests library-tests server-tests util-tests)
diff --git a/unit_tests/engine/base64.cpp b/unit_tests/engine/base64.cpp
index 4896965..f0515fc 100644
--- a/unit_tests/engine/base64.cpp
+++ b/unit_tests/engine/base64.cpp
@@ -16,7 +16,6 @@ BOOST_AUTO_TEST_CASE(rfc4648_test_vectors)
{
using namespace osrm::engine;
- BOOST_CHECK_EQUAL(encodeBase64(""), "");
BOOST_CHECK_EQUAL(encodeBase64("f"), "Zg==");
BOOST_CHECK_EQUAL(encodeBase64("fo"), "Zm8=");
BOOST_CHECK_EQUAL(encodeBase64("foo"), "Zm9v");
@@ -29,7 +28,6 @@ BOOST_AUTO_TEST_CASE(rfc4648_test_vectors_roundtrip)
{
using namespace osrm::engine;
- BOOST_CHECK_EQUAL(decodeBase64(encodeBase64("")), "");
BOOST_CHECK_EQUAL(decodeBase64(encodeBase64("f")), "f");
BOOST_CHECK_EQUAL(decodeBase64(encodeBase64("fo")), "fo");
BOOST_CHECK_EQUAL(decodeBase64(encodeBase64("foo")), "foo");
diff --git a/unit_tests/engine/douglas_peucker.cpp b/unit_tests/engine/douglas_peucker.cpp
index b280c13..2a1a7a3 100644
--- a/unit_tests/engine/douglas_peucker.cpp
+++ b/unit_tests/engine/douglas_peucker.cpp
@@ -1,4 +1,5 @@
#include "engine/douglas_peucker.hpp"
+#include "util/coordinate_calculation.hpp"
#include <boost/test/unit_test.hpp>
#include <boost/test/test_case_template.hpp>
@@ -12,6 +13,16 @@ BOOST_AUTO_TEST_SUITE(douglas_peucker_simplification)
using namespace osrm;
using namespace osrm::engine;
+BOOST_AUTO_TEST_CASE(calibrate_thresholds)
+{
+ auto thresholds = detail::generateThreshold(5, 19);
+ auto z = 0;
+ for (auto t : thresholds)
+ {
+ BOOST_TEST_MESSAGE(t << ", // z" << z++);
+ }
+}
+
BOOST_AUTO_TEST_CASE(removed_middle_test)
{
/*
@@ -23,9 +34,9 @@ BOOST_AUTO_TEST_CASE(removed_middle_test)
*/
std::vector<util::Coordinate> coordinates = {
util::Coordinate(util::FloatLongitude(5), util::FloatLatitude(5)),
- util::Coordinate(util::FloatLongitude(5.995715), util::FloatLatitude(6)),
- util::Coordinate(util::FloatLongitude(10), util::FloatLatitude(10)),
- util::Coordinate(util::FloatLongitude(15), util::FloatLatitude(5))};
+ util::Coordinate(util::FloatLongitude(12.5), util::FloatLatitude(12.6096298302)),
+ util::Coordinate(util::FloatLongitude(20), util::FloatLatitude(20)),
+ util::Coordinate(util::FloatLongitude(25), util::FloatLatitude(5))};
for (unsigned z = 0; z < detail::DOUGLAS_PEUCKER_THRESHOLDS_SIZE; z++)
{
@@ -49,19 +60,19 @@ BOOST_AUTO_TEST_CASE(removed_middle_test_zoom_sensitive)
std::vector<util::Coordinate> coordinates = {
util::Coordinate(util::FloatLongitude(5), util::FloatLatitude(5)),
util::Coordinate(util::FloatLongitude(6), util::FloatLatitude(6)),
- util::Coordinate(util::FloatLongitude(10), util::FloatLatitude(10)),
- util::Coordinate(util::FloatLongitude(15), util::FloatLatitude(5))};
+ util::Coordinate(util::FloatLongitude(20), util::FloatLatitude(20)),
+ util::Coordinate(util::FloatLongitude(25), util::FloatLatitude(5))};
- // Coordinate 6,6 should start getting included at Z12 and higher
+ // Coordinate 6,6 should start getting included at Z9 and higher
// Note that 5,5->6,6->10,10 is *not* a straight line on the surface
// of the earth
- for (unsigned z = 0; z < 11; z++)
+ for (unsigned z = 0; z < 9; z++)
{
auto result = douglasPeucker(coordinates, z);
BOOST_CHECK_EQUAL(result.size(), 3);
}
- // From 12 to max zoom, we should get all coordinates
- for (unsigned z = 12; z < detail::DOUGLAS_PEUCKER_THRESHOLDS_SIZE; z++)
+ // From 9 to max zoom, we should get all coordinates
+ for (unsigned z = 9; z < detail::DOUGLAS_PEUCKER_THRESHOLDS_SIZE; z++)
{
auto result = douglasPeucker(coordinates, z);
BOOST_CHECK_EQUAL(result.size(), 4);
@@ -71,38 +82,39 @@ BOOST_AUTO_TEST_CASE(removed_middle_test_zoom_sensitive)
BOOST_AUTO_TEST_CASE(remove_second_node_test)
{
- for (unsigned z = 0; z < detail::DOUGLAS_PEUCKER_THRESHOLDS_SIZE; z++)
+ // derived from the degreeToPixel function
+ const auto delta_pixel_to_delta_degree = [](const int pixel, const unsigned zoom) {
+ const double shift = (1u << zoom) * 256;
+ const double b = shift / 2.0;
+ return pixel * 180. / b;
+ };
+ // For zoom level 0 all gets reduced to a line
+ for (unsigned z = 1; z < detail::DOUGLAS_PEUCKER_THRESHOLDS_SIZE; z++)
{
/*
- x--x
- | \
- x-x x
- |
- x
+ x
+ | \
+ x-x x
+ |
+ x
*/
std::vector<util::Coordinate> input = {
- util::Coordinate(util::FixedLongitude(5 * COORDINATE_PRECISION),
- util::FixedLatitude(5 * COORDINATE_PRECISION)),
- util::Coordinate(util::FixedLongitude(5 * COORDINATE_PRECISION),
- util::FixedLatitude(5 * COORDINATE_PRECISION +
- detail::DOUGLAS_PEUCKER_THRESHOLDS[z])),
- util::Coordinate(util::FixedLongitude(10 * COORDINATE_PRECISION),
- util::FixedLatitude(10 * COORDINATE_PRECISION)),
- util::Coordinate(util::FixedLongitude(10 * COORDINATE_PRECISION),
- util::FixedLatitude(10 + COORDINATE_PRECISION +
- detail::DOUGLAS_PEUCKER_THRESHOLDS[z] * 2)),
- util::Coordinate(util::FixedLongitude(5 * COORDINATE_PRECISION),
- util::FixedLatitude(15 * COORDINATE_PRECISION)),
- util::Coordinate(util::FixedLongitude(5 * COORDINATE_PRECISION +
- detail::DOUGLAS_PEUCKER_THRESHOLDS[z]),
- util::FixedLatitude(15 * COORDINATE_PRECISION))};
- BOOST_TEST_MESSAGE("Threshold (" << z << "): " << detail::DOUGLAS_PEUCKER_THRESHOLDS[z]);
+ util::Coordinate(util::FloatLongitude(5),
+ util::FloatLatitude(5)),
+ util::Coordinate(util::FloatLongitude(5 + delta_pixel_to_delta_degree(2, z)),
+ util::FloatLatitude(5)),
+ util::Coordinate(util::FloatLongitude(10),
+ util::FloatLatitude(10)),
+ util::Coordinate(util::FloatLongitude(5),
+ util::FloatLatitude(15)),
+ util::Coordinate(util::FloatLongitude(5),
+ util::FloatLatitude(15 + delta_pixel_to_delta_degree(2, z)))};
+ BOOST_TEST_MESSAGE("Delta (" << z << "): " << delta_pixel_to_delta_degree(2, z));
auto result = douglasPeucker(input, z);
- BOOST_CHECK_EQUAL(result.size(), 4);
+ BOOST_CHECK_EQUAL(result.size(), 3);
BOOST_CHECK_EQUAL(input[0], result[0]);
BOOST_CHECK_EQUAL(input[2], result[1]);
- BOOST_CHECK_EQUAL(input[3], result[2]);
- BOOST_CHECK_EQUAL(input[5], result[3]);
+ BOOST_CHECK_EQUAL(input[4], result[2]);
}
}
diff --git a/unit_tests/library/equal_json.hpp b/unit_tests/library/equal_json.hpp
index 8e2f9ac..1453086 100644
--- a/unit_tests/library/equal_json.hpp
+++ b/unit_tests/library/equal_json.hpp
@@ -1,12 +1,13 @@
#ifndef UNIT_TESTS_JSON_EQUAL
#define UNIT_TESTS_JSON_EQUAL
-#include <boost/test/included/unit_test.hpp>
+#include <boost/test/unit_test.hpp>
+#include "osrm/json_container.hpp"
#include "util/json_deep_compare.hpp"
-boost::test_tools::predicate_result compareJSON(const osrm::util::json::Value &reference,
- const osrm::util::json::Value &result)
+inline boost::test_tools::predicate_result compareJSON(const osrm::util::json::Value &reference,
+ const osrm::util::json::Value &result)
{
std::string reason;
auto is_same = osrm::util::json::compare(reference, result, reason);
diff --git a/unit_tests/library/match.cpp b/unit_tests/library/match.cpp
index 5cd2739..37d36c2 100644
--- a/unit_tests/library/match.cpp
+++ b/unit_tests/library/match.cpp
@@ -3,6 +3,7 @@
#include "args.hpp"
#include "fixture.hpp"
+#include "coordinates.hpp"
#include "osrm/match_parameters.hpp"
@@ -23,15 +24,44 @@ BOOST_AUTO_TEST_CASE(test_match)
auto osrm = getOSRM(args[0]);
- /*
MatchParameters params;
+ params.coordinates.push_back(get_dummy_location());
+ params.coordinates.push_back(get_dummy_location());
+ params.coordinates.push_back(get_dummy_location());
json::Object result;
const auto rc = osrm.Match(params, result);
BOOST_CHECK(rc == Status::Ok || rc == Status::Error);
- */
+ const auto code = result.values.at("code").get<json::String>().value;
+ BOOST_CHECK_EQUAL(code, "Ok");
+
+ const auto &tracepoints = result.values.at("tracepoints").get<json::Array>().values;
+ BOOST_CHECK_EQUAL(tracepoints.size(), params.coordinates.size());
+
+ const auto &matchings = result.values.at("matchings").get<json::Array>().values;
+ const auto &number_of_matchings = matchings.size();
+ for (const auto &waypoint : tracepoints)
+ {
+ if (waypoint.is<mapbox::util::recursive_wrapper<util::json::Object>>())
+ {
+ const auto &waypoint_object = waypoint.get<json::Object>();
+ const auto &waypoint_object_location = waypoint_object.values.at("location").get<json::Array>().values;
+ util::FloatLongitude lon(waypoint_object_location[0].get<json::Number>().value);
+ util::FloatLatitude lat(waypoint_object_location[1].get<json::Number>().value);
+ util::Coordinate location_coordinate(lon, lat);
+ BOOST_CHECK(location_coordinate.IsValid());
+ const auto matchings_index = waypoint_object.values.at("matchings_index").get<json::Number>().value;
+ const auto waypoint_index = waypoint_object.values.at("waypoint_index").get<json::Number>().value;
+ const auto &route_legs = matchings[matchings_index].get<json::Object>().values.at("legs").get<json::Array>().values;
+ BOOST_CHECK_LT(waypoint_index, route_legs.size() + 1);
+ BOOST_CHECK_LT(matchings_index, number_of_matchings);
+ } else
+ {
+ BOOST_CHECK(waypoint.is<json::Null>());
+ }
+ }
}
BOOST_AUTO_TEST_SUITE_END()
diff --git a/unit_tests/library/nearest.cpp b/unit_tests/library/nearest.cpp
index b56f0f7..1685d94 100644
--- a/unit_tests/library/nearest.cpp
+++ b/unit_tests/library/nearest.cpp
@@ -30,7 +30,7 @@ BOOST_AUTO_TEST_CASE(test_nearest_response)
BOOST_REQUIRE(rc == Status::Ok);
const auto code = result.values.at("code").get<json::String>().value;
- BOOST_CHECK_EQUAL(code, "ok");
+ BOOST_CHECK_EQUAL(code, "Ok");
const auto &waypoints = result.values.at("waypoints").get<json::Array>().values;
BOOST_CHECK(!waypoints.empty()); // the dataset has at least one nearest coordinate
@@ -97,7 +97,7 @@ BOOST_AUTO_TEST_CASE(test_nearest_response_for_location_in_small_component)
BOOST_REQUIRE(rc == Status::Ok);
const auto code = result.values.at("code").get<json::String>().value;
- BOOST_CHECK_EQUAL(code, "ok");
+ BOOST_CHECK_EQUAL(code, "Ok");
const auto &waypoints = result.values.at("waypoints").get<json::Array>().values;
BOOST_CHECK(!waypoints.empty());
diff --git a/unit_tests/library/route.cpp b/unit_tests/library/route.cpp
index e93ceba..f9aaae9 100644
--- a/unit_tests/library/route.cpp
+++ b/unit_tests/library/route.cpp
@@ -1,18 +1,18 @@
-#include <boost/test/unit_test.hpp>
#include <boost/test/test_case_template.hpp>
+#include <boost/test/unit_test.hpp>
#include "args.hpp"
-#include "fixture.hpp"
-#include "equal_json.hpp"
#include "coordinates.hpp"
-
-#include "osrm/route_parameters.hpp"
+#include "equal_json.hpp"
+#include "fixture.hpp"
#include "osrm/coordinate.hpp"
#include "osrm/engine_config.hpp"
#include "osrm/json_container.hpp"
-#include "osrm/status.hpp"
+#include "osrm/json_container.hpp"
#include "osrm/osrm.hpp"
+#include "osrm/route_parameters.hpp"
+#include "osrm/status.hpp"
BOOST_AUTO_TEST_SUITE(route)
@@ -24,6 +24,7 @@ BOOST_AUTO_TEST_CASE(test_route_same_coordinates_fixture)
using namespace osrm;
RouteParameters params;
+ params.steps = true;
params.coordinates.push_back(get_dummy_location());
params.coordinates.push_back(get_dummy_location());
@@ -31,33 +32,52 @@ BOOST_AUTO_TEST_CASE(test_route_same_coordinates_fixture)
const auto rc = osrm.Route(params, result);
BOOST_CHECK(rc == Status::Ok);
+ // unset snapping dependent hint
+ for (auto &itr : result.values["waypoints"].get<json::Array>().values)
+ itr.get<json::Object>().values["hint"] = "";
+
+ const auto location = json::Array{{{7.437070}, {43.749247}}};
+
json::Object reference{
- {{"code", "ok"},
+ {{"code", "Ok"},
{"waypoints",
- json::Array{{json::Object{{{"name", ""}, {"location", json::Array{}}, {"hint", ""}}},
- json::Object{{{"name", ""}, {"location", json::Array{}}, {"hint", ""}}}}}},
- {"routes", json::Array{{json::Object{
- {{"distance", 0.},
- {"duration", 0.},
- {"geometry", ""},
- {"legs", json::Array{{json::Object{
- {{"distance", 0.},
- {"duration", 0.},
- {"summary", ""},
- {"steps", json::Array{{json::Object{
- {{"duration", 0.},
- {"distance", 0.},
- {"geometry", ""},
- {"name", ""},
- {"mode", "driving"},
- {"maneuver", json::Object{{
- {"type", "depart"},
- {"location", json::Array{}},
- {"modifier", ""},
- {"bearing_before", 0.},
- {"bearing_after", 0.},
- {"exit", 0},
- }}}}}}}}}}}}}}}}}}}};
+ json::Array{
+ {json::Object{
+ {{"name", "Boulevard du Larvotto"}, {"location", location}, {"hint", ""}}},
+ json::Object{
+ {{"name", "Boulevard du Larvotto"}, {"location", location}, {"hint", ""}}}}}},
+ {"routes",
+ json::Array{{json::Object{
+ {{"distance", 0.},
+ {"duration", 0.},
+ {"geometry", "yw_jGupkl@??"},
+ {"legs",
+ json::Array{{json::Object{
+ {{"distance", 0.},
+ {"duration", 0.},
+ {"steps", json::Array{{json::Object{{{"duration", 0.},
+ {"distance", 0.},
+ {"geometry", "yw_jGupkl@??"},
+ {"name", "Boulevard du Larvotto"},
+ {"mode", "driving"},
+ {"maneuver", json::Object{{
+ {"type", "depart"},
+ {"location", location},
+ {"bearing_before", 0.},
+ {"bearing_after", 0.},
+ }}}}},
+
+ json::Object{{{"duration", 0.},
+ {"distance", 0.},
+ {"geometry", "yw_jGupkl@"},
+ {"name", "Boulevard du Larvotto"},
+ {"mode", "driving"},
+ {"maneuver", json::Object{{
+ {"type", "arrive"},
+ {"location", location},
+ {"bearing_before", 0.},
+ {"bearing_after", 0.},
+ }}}}}}}}}}}}}}}}}}}};
CHECK_EQUAL_JSON(reference, result);
}
@@ -70,6 +90,7 @@ BOOST_AUTO_TEST_CASE(test_route_same_coordinates)
using namespace osrm;
RouteParameters params;
+ params.steps = true;
params.coordinates.push_back(get_dummy_location());
params.coordinates.push_back(get_dummy_location());
params.coordinates.push_back(get_dummy_location());
@@ -79,7 +100,7 @@ BOOST_AUTO_TEST_CASE(test_route_same_coordinates)
BOOST_CHECK(rc == Status::Ok);
const auto code = result.values.at("code").get<json::String>().value;
- BOOST_CHECK_EQUAL(code, "ok");
+ BOOST_CHECK_EQUAL(code, "Ok");
const auto &waypoints = result.values.at("waypoints").get<json::Array>().values;
BOOST_CHECK(waypoints.size() == params.coordinates.size());
@@ -102,10 +123,8 @@ BOOST_AUTO_TEST_CASE(test_route_same_coordinates)
BOOST_CHECK(!hint.empty());
}
- // alternative=true by default
const auto &routes = result.values.at("routes").get<json::Array>().values;
- BOOST_CHECK(!routes.empty());
- BOOST_CHECK(routes.size() > 1);
+ BOOST_REQUIRE_GT(routes.size(), 0);
for (const auto &route : routes)
{
@@ -134,11 +153,6 @@ BOOST_AUTO_TEST_CASE(test_route_same_coordinates)
const auto duration = leg_object.values.at("duration").get<json::Number>().value;
BOOST_CHECK_EQUAL(duration, 0);
- // nothing can be said about summary, empty or contains human readable summary
- const auto summary = leg_object.values.at("summary").get<json::String>().value;
- BOOST_CHECK(((void)summary, true));
-
- // steps=true by default
const auto &steps = leg_object.values.at("steps").get<json::Array>().values;
BOOST_CHECK(!steps.empty());
@@ -209,7 +223,7 @@ BOOST_AUTO_TEST_CASE(test_route_response_for_locations_in_small_component)
BOOST_CHECK(rc == Status::Ok);
const auto code = result.values.at("code").get<json::String>().value;
- BOOST_CHECK_EQUAL(code, "ok");
+ BOOST_CHECK_EQUAL(code, "Ok");
const auto &waypoints = result.values.at("waypoints").get<json::Array>().values;
BOOST_CHECK_EQUAL(waypoints.size(), params.coordinates.size());
diff --git a/unit_tests/mocks/mock_datafacade.hpp b/unit_tests/mocks/mock_datafacade.hpp
index cb05a94..f608b66 100644
--- a/unit_tests/mocks/mock_datafacade.hpp
+++ b/unit_tests/mocks/mock_datafacade.hpp
@@ -170,7 +170,7 @@ class MockDataFacade final : public engine::datafacade::BaseDataFacade
std::string GetNameForID(const unsigned /* name_id */) const override { return ""; }
std::size_t GetCoreSize() const override { return 0; }
std::string GetTimestamp() const override { return ""; }
- bool GetUTurnsDefault() const override { return true; }
+ bool GetContinueStraightDefault() const override { return true; }
};
} // ns test
} // ns osrm
diff --git a/unit_tests/server/parameters_parser.cpp b/unit_tests/server/parameters_parser.cpp
index e6f2d82..1b5161f 100644
--- a/unit_tests/server/parameters_parser.cpp
+++ b/unit_tests/server/parameters_parser.cpp
@@ -1,12 +1,12 @@
#include "server/api/parameters_parser.hpp"
#include "engine/api/base_parameters.hpp"
+#include "engine/api/match_parameters.hpp"
+#include "engine/api/nearest_parameters.hpp"
#include "engine/api/route_parameters.hpp"
#include "engine/api/table_parameters.hpp"
-#include "engine/api/match_parameters.hpp"
-#include "engine/api/trip_parameters.hpp"
#include "engine/api/tile_parameters.hpp"
-#include "engine/api/nearest_parameters.hpp"
+#include "engine/api/trip_parameters.hpp"
#include <fstream>
@@ -58,9 +58,9 @@ std::ostream &operator<<(std::ostream &out, Bearing bearing)
}
}
-#include <boost/test/unit_test.hpp>
-#include <boost/test/test_tools.hpp>
#include <boost/optional/optional_io.hpp>
+#include <boost/test/test_tools.hpp>
+#include <boost/test/unit_test.hpp>
#define CHECK_EQUAL_RANGE(R1, R2) \
BOOST_CHECK_EQUAL_COLLECTIONS(R1.begin(), R1.end(), R2.begin(), R2.end());
@@ -87,13 +87,13 @@ BOOST_AUTO_TEST_CASE(invalid_route_urls)
testInvalidOptions<engine::api::RouteParameters>("1,2;3,4?overview=false&bearings=foo"),
32UL);
BOOST_CHECK_EQUAL(
- testInvalidOptions<engine::api::RouteParameters>("1,2;3,4?overview=false&uturns=foo"),
- 30UL);
+ testInvalidOptions<engine::api::RouteParameters>("1,2;3,4?overview=false&continue_straight=foo"),
+ 41UL);
BOOST_CHECK_EQUAL(
testInvalidOptions<engine::api::RouteParameters>("1,2;3,4?overview=false&radiuses=foo"),
32UL);
BOOST_CHECK_EQUAL(
- testInvalidOptions<engine::api::RouteParameters>("1,2;3,4?overview=false&hints=foo"), 22UL);
+ testInvalidOptions<engine::api::RouteParameters>("1,2;3,4?overview=false&hints=foo"), 29UL);
BOOST_CHECK_EQUAL(
testInvalidOptions<engine::api::RouteParameters>("1,2;3,4?overview=false&geometries=foo"),
22UL);
@@ -102,7 +102,7 @@ BOOST_AUTO_TEST_CASE(invalid_route_urls)
22L);
BOOST_CHECK_EQUAL(
testInvalidOptions<engine::api::RouteParameters>("1,2;3,4?overview=false&alternatives=foo"),
- 22UL);
+ 36UL);
}
BOOST_AUTO_TEST_CASE(invalid_table_urls)
@@ -114,9 +114,10 @@ BOOST_AUTO_TEST_CASE(invalid_table_urls)
BOOST_CHECK_EQUAL(testInvalidOptions<engine::api::TableParameters>(
"1,2;3,4?sources=1&destinations=1&bla=foo"),
32UL);
- BOOST_CHECK_EQUAL(testInvalidOptions<engine::api::TableParameters>("1,2;3,4?sources=foo"), 7UL);
+ BOOST_CHECK_EQUAL(testInvalidOptions<engine::api::TableParameters>("1,2;3,4?sources=foo"),
+ 16UL);
BOOST_CHECK_EQUAL(testInvalidOptions<engine::api::TableParameters>("1,2;3,4?destinations=foo"),
- 7UL);
+ 21UL);
}
BOOST_AUTO_TEST_CASE(valid_route_urls)
@@ -132,12 +133,14 @@ BOOST_AUTO_TEST_CASE(valid_route_urls)
BOOST_CHECK_EQUAL(reference_1.alternatives, result_1->alternatives);
BOOST_CHECK_EQUAL(reference_1.geometries, result_1->geometries);
BOOST_CHECK_EQUAL(reference_1.overview, result_1->overview);
- BOOST_CHECK_EQUAL(reference_1.uturns, result_1->uturns);
+ BOOST_CHECK_EQUAL(reference_1.continue_straight, result_1->continue_straight);
CHECK_EQUAL_RANGE(reference_1.bearings, result_1->bearings);
CHECK_EQUAL_RANGE(reference_1.radiuses, result_1->radiuses);
CHECK_EQUAL_RANGE(reference_1.coordinates, result_1->coordinates);
engine::api::RouteParameters reference_2{};
+ reference_2.alternatives = true;
+ reference_2.steps = true;
reference_2.coordinates = coords_1;
auto result_2 = api::parseParameters<engine::api::RouteParameters>(
"1,2;3,4?steps=true&alternatives=true&geometries=polyline&overview=simplified");
@@ -146,39 +149,39 @@ BOOST_AUTO_TEST_CASE(valid_route_urls)
BOOST_CHECK_EQUAL(reference_2.alternatives, result_2->alternatives);
BOOST_CHECK_EQUAL(reference_2.geometries, result_2->geometries);
BOOST_CHECK_EQUAL(reference_2.overview, result_2->overview);
- BOOST_CHECK_EQUAL(reference_2.uturns, result_2->uturns);
+ BOOST_CHECK_EQUAL(reference_2.continue_straight, result_2->continue_straight);
CHECK_EQUAL_RANGE(reference_2.bearings, result_2->bearings);
CHECK_EQUAL_RANGE(reference_2.radiuses, result_2->radiuses);
CHECK_EQUAL_RANGE(reference_2.coordinates, result_2->coordinates);
- engine::api::RouteParameters reference_3{false,
- false,
- engine::api::RouteParameters::GeometriesType::GeoJSON,
- engine::api::RouteParameters::OverviewType::False,
- true};
+ engine::api::RouteParameters reference_3{
+ false, false, engine::api::RouteParameters::GeometriesType::GeoJSON,
+ engine::api::RouteParameters::OverviewType::False, true};
reference_3.coordinates = coords_1;
auto result_3 = api::parseParameters<engine::api::RouteParameters>(
- "1,2;3,4?steps=false&alternatives=false&geometries=geojson&overview=false&uturns=true"
- "false;");
+ "1,2;3,4?steps=false&alternatives=false&geometries=geojson&overview=false&continue_straight=true");
BOOST_CHECK(result_3);
BOOST_CHECK_EQUAL(reference_3.steps, result_3->steps);
BOOST_CHECK_EQUAL(reference_3.alternatives, result_3->alternatives);
BOOST_CHECK_EQUAL(reference_3.geometries, result_3->geometries);
BOOST_CHECK_EQUAL(reference_3.overview, result_3->overview);
- BOOST_CHECK_EQUAL(reference_3.uturns, result_3->uturns);
+ BOOST_CHECK_EQUAL(reference_3.continue_straight, result_3->continue_straight);
CHECK_EQUAL_RANGE(reference_3.bearings, result_3->bearings);
CHECK_EQUAL_RANGE(reference_3.radiuses, result_3->radiuses);
CHECK_EQUAL_RANGE(reference_3.coordinates, result_3->coordinates);
std::vector<boost::optional<engine::Hint>> hints_4 = {
- engine::Hint::FromBase64(
- "rVghAzxMzABMAwAA5h4CAKMIAAAQAAAAGAAAAAYAAAAAAAAAch8BAJ4AAACpWCED_0vMAAEAAQGLSzmR"),
- engine::Hint::FromBase64(
- "_4ghA4JuzAD_IAAAo28BAOYAAAAzAAAAAgAAAEwAAAAAAAAAdIwAAJ4AAAAXiSEDfm7MAAEAAQGLSzmR"),
- engine::Hint::FromBase64(
- "03AhA0vnzAA_SAAA_____3wEAAAYAAAAQAAAAB4AAABAAAAAoUYBAJ4AAADlcCEDSefMAAMAAQGLSzmR")};
+ engine::Hint::FromBase64("DAIAgP___"
+ "38AAAAAAAAAAAIAAAAAAAAAEAAAAOgDAAD0AwAAGwAAAOUacQBQP5sCshpxAB0_"
+ "mwIAAAEBl-Umfg=="),
+ engine::Hint::FromBase64("cgAAgP___"
+ "39jAAAADgAAACIAAABeAAAAkQAAANoDAABOAgAAGwAAAFVGcQCiRJsCR0VxAOZFmw"
+ "IFAAEBl-Umfg=="),
+ engine::Hint::FromBase64("3gAAgP___"
+ "39KAAAAHgAAACEAAAAAAAAAGAAAAE0BAABOAQAAGwAAAIAzcQBkUJsC1zNxAHBQmw"
+ "IAAAEBl-Umfg==")};
engine::api::RouteParameters reference_4{false,
- true,
+ false,
engine::api::RouteParameters::GeometriesType::Polyline,
engine::api::RouteParameters::OverviewType::Simplified,
boost::optional<bool>{},
@@ -188,16 +191,15 @@ BOOST_AUTO_TEST_CASE(valid_route_urls)
std::vector<boost::optional<engine::Bearing>>{}};
auto result_4 = api::parseParameters<engine::api::RouteParameters>(
"1,2;3,4?steps=false&hints="
- "rVghAzxMzABMAwAA5h4CAKMIAAAQAAAAGAAAAAYAAAAAAAAAch8BAJ4AAACpWCED_"
- "0vMAAEAAQGLSzmR;_4ghA4JuzAD_"
- "IAAAo28BAOYAAAAzAAAAAgAAAEwAAAAAAAAAdIwAAJ4AAAAXiSEDfm7MAAEAAQGLSzmR;03AhA0vnzAA_SAAA_____"
- "3wEAAAYAAAAQAAAAB4AAABAAAAAoUYBAJ4AAADlcCEDSefMAAMAAQGLSzmR");
+ "DAIAgP___38AAAAAAAAAAAIAAAAAAAAAEAAAAOgDAAD0AwAAGwAAAOUacQBQP5sCshpxAB0_mwIAAAEBl-Umfg==;"
+ "cgAAgP___39jAAAADgAAACIAAABeAAAAkQAAANoDAABOAgAAGwAAAFVGcQCiRJsCR0VxAOZFmwIFAAEBl-Umfg==;"
+ "3gAAgP___39KAAAAHgAAACEAAAAAAAAAGAAAAE0BAABOAQAAGwAAAIAzcQBkUJsC1zNxAHBQmwIAAAEBl-Umfg==");
BOOST_CHECK(result_4);
BOOST_CHECK_EQUAL(reference_4.steps, result_4->steps);
BOOST_CHECK_EQUAL(reference_4.alternatives, result_4->alternatives);
BOOST_CHECK_EQUAL(reference_4.geometries, result_4->geometries);
BOOST_CHECK_EQUAL(reference_4.overview, result_4->overview);
- BOOST_CHECK_EQUAL(reference_4.uturns, result_4->uturns);
+ BOOST_CHECK_EQUAL(reference_4.continue_straight, result_4->continue_straight);
CHECK_EQUAL_RANGE(reference_4.bearings, result_4->bearings);
CHECK_EQUAL_RANGE(reference_4.radiuses, result_4->radiuses);
CHECK_EQUAL_RANGE(reference_4.coordinates, result_4->coordinates);
@@ -206,7 +208,7 @@ BOOST_AUTO_TEST_CASE(valid_route_urls)
boost::none, engine::Bearing{200, 10}, engine::Bearing{100, 5},
};
engine::api::RouteParameters reference_5{false,
- true,
+ false,
engine::api::RouteParameters::GeometriesType::Polyline,
engine::api::RouteParameters::OverviewType::Simplified,
boost::optional<bool>{},
@@ -221,7 +223,7 @@ BOOST_AUTO_TEST_CASE(valid_route_urls)
BOOST_CHECK_EQUAL(reference_5.alternatives, result_5->alternatives);
BOOST_CHECK_EQUAL(reference_5.geometries, result_5->geometries);
BOOST_CHECK_EQUAL(reference_5.overview, result_5->overview);
- BOOST_CHECK_EQUAL(reference_5.uturns, result_5->uturns);
+ BOOST_CHECK_EQUAL(reference_5.continue_straight, result_5->continue_straight);
CHECK_EQUAL_RANGE(reference_5.bearings, result_5->bearings);
CHECK_EQUAL_RANGE(reference_5.radiuses, result_5->radiuses);
CHECK_EQUAL_RANGE(reference_5.coordinates, result_5->coordinates);
@@ -239,7 +241,7 @@ BOOST_AUTO_TEST_CASE(valid_route_urls)
BOOST_CHECK_EQUAL(reference_6.alternatives, result_6->alternatives);
BOOST_CHECK_EQUAL(reference_6.geometries, result_6->geometries);
BOOST_CHECK_EQUAL(reference_6.overview, result_6->overview);
- BOOST_CHECK_EQUAL(reference_6.uturns, result_6->uturns);
+ BOOST_CHECK_EQUAL(reference_6.continue_straight, result_6->continue_straight);
CHECK_EQUAL_RANGE(reference_6.bearings, result_6->bearings);
CHECK_EQUAL_RANGE(reference_6.radiuses, result_6->radiuses);
CHECK_EQUAL_RANGE(reference_6.coordinates, result_6->coordinates);
diff --git a/unit_tests/server/url_parser.cpp b/unit_tests/server/url_parser.cpp
index 1405674..cca1f61 100644
--- a/unit_tests/server/url_parser.cpp
+++ b/unit_tests/server/url_parser.cpp
@@ -19,8 +19,8 @@ std::ostream &operator<<(std::ostream &out, const osrm::server::api::ParsedURL &
}
}
-#include <boost/test/unit_test.hpp>
#include <boost/test/test_tools.hpp>
+#include <boost/test/unit_test.hpp>
#define CHECK_EQUAL_RANGE(R1, R2) \
BOOST_CHECK_EQUAL_COLLECTIONS(R1.begin(), R1.end(), R2.begin(), R2.end());
@@ -41,12 +41,12 @@ std::size_t testInvalidURL(std::string url)
BOOST_AUTO_TEST_CASE(invalid_urls)
{
- BOOST_CHECK_EQUAL(testInvalidURL("/route/"), 0UL);
- BOOST_CHECK_EQUAL(testInvalidURL("/route/bla"), 0UL);
- BOOST_CHECK_EQUAL(testInvalidURL("/route/1/1,2;3;4"), 0UL);
- BOOST_CHECK_EQUAL(testInvalidURL("/route/v1/pro_file/1,2;3,4"), 0UL);
- BOOST_CHECK_EQUAL(testInvalidURL("/route/v1/profile"), 0UL);
- BOOST_CHECK_EQUAL(testInvalidURL("/route/v1/profile/"), 0UL);
+ BOOST_CHECK_EQUAL(testInvalidURL("/route/"), 7UL);
+ BOOST_CHECK_EQUAL(testInvalidURL("/route/bla"), 7UL);
+ BOOST_CHECK_EQUAL(testInvalidURL("/route/1/1,2;3;4"), 7UL);
+ BOOST_CHECK_EQUAL(testInvalidURL("/route/v1/pro_file/1,2;3,4"), 13UL);
+ BOOST_CHECK_EQUAL(testInvalidURL("/route/v1/profile"), 17UL);
+ BOOST_CHECK_EQUAL(testInvalidURL("/route/v1/profile/"), 18UL);
}
BOOST_AUTO_TEST_CASE(valid_urls)
diff --git a/unit_tests/util/coordinate_calculation.cpp b/unit_tests/util/coordinate_calculation.cpp
index d159441..0515a36 100644
--- a/unit_tests/util/coordinate_calculation.cpp
+++ b/unit_tests/util/coordinate_calculation.cpp
@@ -1,4 +1,5 @@
#include <boost/test/unit_test.hpp>
+#include <boost/numeric/conversion/cast.hpp>
#include "util/coordinate_calculation.hpp"
@@ -11,6 +12,130 @@ using namespace osrm::util;
BOOST_AUTO_TEST_SUITE(coordinate_calculation_tests)
+BOOST_AUTO_TEST_CASE(compute_angle)
+{
+ // Simple cases
+ // North-South straight line
+ Coordinate first(FloatLongitude(1), FloatLatitude(-1));
+ Coordinate middle(FloatLongitude(1), FloatLatitude(0));
+ Coordinate end(FloatLongitude(1), FloatLatitude(1));
+ auto angle = coordinate_calculation::computeAngle(first, middle, end);
+ BOOST_CHECK_EQUAL(angle, 180);
+
+ // North-South-North u-turn
+ first = Coordinate(FloatLongitude(1), FloatLatitude(0));
+ middle = Coordinate(FloatLongitude(1), FloatLatitude(1));
+ end = Coordinate(FloatLongitude(1), FloatLatitude(0));
+ angle = coordinate_calculation::computeAngle(first, middle, end);
+ BOOST_CHECK_EQUAL(angle, 0);
+
+ // East-west straight lines are harder, *simple* coordinates only
+ // work at the equator. For other locations, we need to follow
+ // a rhumb line.
+ first = Coordinate(FloatLongitude(1), FloatLatitude(0));
+ middle = Coordinate(FloatLongitude(2), FloatLatitude(0));
+ end = Coordinate(FloatLongitude(3), FloatLatitude(0));
+ angle = coordinate_calculation::computeAngle(first, middle, end);
+ BOOST_CHECK_EQUAL(angle, 180);
+
+ // East-West-East u-turn
+ first = Coordinate(FloatLongitude(1), FloatLatitude(0));
+ middle = Coordinate(FloatLongitude(2), FloatLatitude(0));
+ end = Coordinate(FloatLongitude(1), FloatLatitude(0));
+ angle = coordinate_calculation::computeAngle(first, middle, end);
+ BOOST_CHECK_EQUAL(angle, 0);
+
+ // 90 degree left turn
+ first = Coordinate(FloatLongitude(1), FloatLatitude(1));
+ middle = Coordinate(FloatLongitude(0), FloatLatitude(1));
+ end = Coordinate(FloatLongitude(0), FloatLatitude(2));
+ angle = coordinate_calculation::computeAngle(first, middle, end);
+ BOOST_CHECK_EQUAL(angle, 90);
+
+ // 90 degree right turn
+ first = Coordinate(FloatLongitude(1), FloatLatitude(1));
+ middle = Coordinate(FloatLongitude(0), FloatLatitude(1));
+ end = Coordinate(FloatLongitude(0), FloatLatitude(0));
+ angle = coordinate_calculation::computeAngle(first, middle, end);
+ BOOST_CHECK_EQUAL(angle, 270);
+
+ // Weird cases
+ // Crossing both the meridians
+ first = Coordinate(FloatLongitude(-1), FloatLatitude(-1));
+ middle = Coordinate(FloatLongitude(0), FloatLatitude(1));
+ end = Coordinate(FloatLongitude(1), FloatLatitude(-1));
+ angle = coordinate_calculation::computeAngle(first, middle, end);
+ BOOST_CHECK_CLOSE(angle, 53.1, 0.2);
+
+ // All coords in the same spot
+ first = Coordinate(FloatLongitude(-1), FloatLatitude(-1));
+ middle = Coordinate(FloatLongitude(-1), FloatLatitude(-1));
+ end = Coordinate(FloatLongitude(-1), FloatLatitude(-1));
+ angle = coordinate_calculation::computeAngle(first, middle, end);
+ BOOST_CHECK_EQUAL(angle, 180);
+
+ // First two coords in the same spot, then heading north-east
+ first = Coordinate(FloatLongitude(-1), FloatLatitude(-1));
+ middle = Coordinate(FloatLongitude(-1), FloatLatitude(-1));
+ end = Coordinate(FloatLongitude(1), FloatLatitude(1));
+ angle = coordinate_calculation::computeAngle(first, middle, end);
+ BOOST_CHECK_EQUAL(angle, 180);
+
+ // First two coords in the same spot, then heading west
+ first = Coordinate(FloatLongitude(1), FloatLatitude(1));
+ middle = Coordinate(FloatLongitude(1), FloatLatitude(1));
+ end = Coordinate(FloatLongitude(2), FloatLatitude(1));
+ angle = coordinate_calculation::computeAngle(first, middle, end);
+ BOOST_CHECK_EQUAL(angle, 180);
+
+ // First two coords in the same spot then heading north
+ first = Coordinate(FloatLongitude(1), FloatLatitude(1));
+ middle = Coordinate(FloatLongitude(1), FloatLatitude(1));
+ end = Coordinate(FloatLongitude(1), FloatLatitude(2));
+ angle = coordinate_calculation::computeAngle(first, middle, end);
+ BOOST_CHECK_EQUAL(angle, 180);
+
+ // Second two coords in the same spot
+ first = Coordinate(FloatLongitude(1), FloatLatitude(1));
+ middle = Coordinate(FloatLongitude(-1), FloatLatitude(-1));
+ end = Coordinate(FloatLongitude(-1), FloatLatitude(-1));
+ angle = coordinate_calculation::computeAngle(first, middle, end);
+ BOOST_CHECK_EQUAL(angle, 180);
+
+ // First and last coords on the same spot
+ first = Coordinate(FloatLongitude(1), FloatLatitude(1));
+ middle = Coordinate(FloatLongitude(-1), FloatLatitude(-1));
+ end = Coordinate(FloatLongitude(1), FloatLatitude(1));
+ angle = coordinate_calculation::computeAngle(first, middle, end);
+ BOOST_CHECK_EQUAL(angle, 0);
+
+ // Check the antimeridian
+ first = Coordinate(FloatLongitude(180), FloatLatitude(90));
+ middle = Coordinate(FloatLongitude(180), FloatLatitude(0));
+ end = Coordinate(FloatLongitude(180), FloatLatitude(-90));
+ angle = coordinate_calculation::computeAngle(first, middle, end);
+ BOOST_CHECK_EQUAL(angle, 180);
+
+ // Tiny changes below our calculation resolution
+ // This should be equivalent to having two points on the same
+ // spot.
+ first = Coordinate(FloatLongitude(0), FloatLatitude(0));
+ middle = Coordinate(FloatLongitude(1), FloatLatitude(0));
+ end = Coordinate(FloatLongitude(1 + std::numeric_limits<double>::epsilon()), FloatLatitude(0));
+ angle = coordinate_calculation::computeAngle(first, middle, end);
+ BOOST_CHECK_EQUAL(angle, 180);
+
+ // Invalid values
+ /* TODO: Enable this when I figure out how to use BOOST_CHECK_THROW
+ * and not have the whole test case fail...
+ first = Coordinate(FloatLongitude(0), FloatLatitude(0));
+ middle = Coordinate(FloatLongitude(1), FloatLatitude(0));
+ end = Coordinate(FloatLongitude(std::numeric_limits<double>::max()), FloatLatitude(0));
+ BOOST_CHECK_THROW( coordinate_calculation::computeAngle(first,middle,end),
+ boost::numeric::positive_overflow);
+ */
+}
+
// Regression test for bug captured in #1347
BOOST_AUTO_TEST_CASE(regression_test_1347)
{
@@ -27,72 +152,6 @@ BOOST_AUTO_TEST_CASE(regression_test_1347)
BOOST_CHECK_LE(std::abs(d1 - d2), 0.01);
}
-BOOST_AUTO_TEST_CASE(lon_to_pixel)
-{
- using namespace coordinate_calculation;
- BOOST_CHECK_CLOSE(7.416042 * mercator::DEGREE_TO_PX, 825550.019142, 0.1);
- BOOST_CHECK_CLOSE(7.415892 * mercator::DEGREE_TO_PX, 825533.321218, 0.1);
- BOOST_CHECK_CLOSE(7.416016 * mercator::DEGREE_TO_PX, 825547.124835, 0.1);
- BOOST_CHECK_CLOSE(7.41577 * mercator::DEGREE_TO_PX, 825519.74024, 0.1);
- BOOST_CHECK_CLOSE(7.415808 * mercator::DEGREE_TO_PX, 825523.970381, 0.1);
-}
-
-BOOST_AUTO_TEST_CASE(lat_to_pixel)
-{
- using namespace coordinate_calculation;
- BOOST_CHECK_CLOSE(mercator::latToY(util::FloatLatitude(43.733947)) * mercator::DEGREE_TO_PX,
- 5424361.75863, 0.1);
- BOOST_CHECK_CLOSE(mercator::latToY(util::FloatLatitude(43.733799)) * mercator::DEGREE_TO_PX,
- 5424338.95731, 0.1);
- BOOST_CHECK_CLOSE(mercator::latToY(util::FloatLatitude(43.733922)) * mercator::DEGREE_TO_PX,
- 5424357.90705, 0.1);
- BOOST_CHECK_CLOSE(mercator::latToY(util::FloatLatitude(43.733697)) * mercator::DEGREE_TO_PX,
- 5424323.24293, 0.1);
- BOOST_CHECK_CLOSE(mercator::latToY(util::FloatLatitude(43.733729)) * mercator::DEGREE_TO_PX,
- 5424328.17293, 0.1);
-}
-
-BOOST_AUTO_TEST_CASE(xyz_to_wgs84)
-{
- using namespace coordinate_calculation;
-
- double minx_1;
- double miny_1;
- double maxx_1;
- double maxy_1;
- mercator::xyzToWGS84(2, 2, 1, minx_1, miny_1, maxx_1, maxy_1);
- BOOST_CHECK_CLOSE(minx_1, 180, 0.0001);
- BOOST_CHECK_CLOSE(miny_1, -85.0511, 0.0001);
- BOOST_CHECK_CLOSE(maxx_1, 360, 0.0001);
- BOOST_CHECK_CLOSE(maxy_1, -85.0511, 0.0001);
-
- double minx_2;
- double miny_2;
- double maxx_2;
- double maxy_2;
- mercator::xyzToWGS84(100, 0, 13, minx_2, miny_2, maxx_2, maxy_2);
- BOOST_CHECK_CLOSE(minx_2, -175.6054, 0.0001);
- BOOST_CHECK_CLOSE(miny_2, 85.0473, 0.0001);
- BOOST_CHECK_CLOSE(maxx_2, -175.5615, 0.0001);
- BOOST_CHECK_CLOSE(maxy_2, 85.0511, 0.0001);
-}
-
-BOOST_AUTO_TEST_CASE(xyz_to_mercator)
-{
- using namespace coordinate_calculation;
-
- double minx;
- double miny;
- double maxx;
- double maxy;
- mercator::xyzToMercator(100, 0, 13, minx, miny, maxx, maxy);
-
- BOOST_CHECK_CLOSE(minx, -19548311.361764118075, 0.0001);
- BOOST_CHECK_CLOSE(miny, 20032616.372979003936, 0.0001);
- BOOST_CHECK_CLOSE(maxx, -19543419.391953866929, 0.0001);
- BOOST_CHECK_CLOSE(maxy, 20037508.342789277434, 0.0001);
-}
-
BOOST_AUTO_TEST_CASE(regression_point_on_segment)
{
// ^
@@ -120,8 +179,10 @@ BOOST_AUTO_TEST_CASE(regression_point_on_segment)
FloatCoordinate diff{target.lon - start.lon, target.lat - start.lat};
- BOOST_CHECK_CLOSE(static_cast<double>(start.lon + FloatLongitude(ratio) * diff.lon), static_cast<double>(nearest.lon), 0.1);
- BOOST_CHECK_CLOSE(static_cast<double>(start.lat + FloatLatitude(ratio) * diff.lat), static_cast<double>(nearest.lat), 0.1);
+ BOOST_CHECK_CLOSE(static_cast<double>(start.lon + FloatLongitude(ratio) * diff.lon),
+ static_cast<double>(nearest.lon), 0.1);
+ BOOST_CHECK_CLOSE(static_cast<double>(start.lat + FloatLatitude(ratio) * diff.lat),
+ static_cast<double>(nearest.lat), 0.1);
}
BOOST_AUTO_TEST_CASE(point_on_segment)
@@ -188,4 +249,53 @@ BOOST_AUTO_TEST_CASE(point_on_segment)
BOOST_CHECK_EQUAL(result_4.second.lat, reference_point_4.lat);
}
+BOOST_AUTO_TEST_CASE(circleCenter)
+{
+ Coordinate a(FloatLongitude(-100.), FloatLatitude(10.));
+ Coordinate b(FloatLongitude(-100.002), FloatLatitude(10.001));
+ Coordinate c(FloatLongitude(-100.001), FloatLatitude(10.002));
+
+ auto result = coordinate_calculation::circleCenter(a, b, c);
+ BOOST_CHECK(result);
+ BOOST_CHECK_EQUAL(*result, Coordinate(FloatLongitude(-100.000833), FloatLatitude(10.000833)));
+
+ // Co-linear longitude
+ a = Coordinate(FloatLongitude(-100.), FloatLatitude(10.));
+ b = Coordinate(FloatLongitude(-100.001), FloatLatitude(10.001));
+ c = Coordinate(FloatLongitude(-100.001), FloatLatitude(10.002));
+ result = coordinate_calculation::circleCenter(a, b, c);
+ BOOST_CHECK(result);
+ BOOST_CHECK_EQUAL(*result, Coordinate(FloatLongitude(-99.9995), FloatLatitude(10.0015)));
+
+ // Co-linear longitude, impossible to calculate
+ a = Coordinate(FloatLongitude(-100.001), FloatLatitude(10.));
+ b = Coordinate(FloatLongitude(-100.001), FloatLatitude(10.001));
+ c = Coordinate(FloatLongitude(-100.001), FloatLatitude(10.002));
+ result = coordinate_calculation::circleCenter(a, b, c);
+ BOOST_CHECK(!result);
+
+ // Co-linear latitude, this is a real case that failed
+ a = Coordinate(FloatLongitude(-112.096234), FloatLatitude(41.147101));
+ b = Coordinate(FloatLongitude(-112.096606), FloatLatitude(41.147101));
+ c = Coordinate(FloatLongitude(-112.096419), FloatLatitude(41.147259));
+ result = coordinate_calculation::circleCenter(a, b, c);
+ BOOST_CHECK(result);
+ BOOST_CHECK_EQUAL(*result, Coordinate(FloatLongitude(-112.09642), FloatLatitude(41.14707)));
+
+ // Co-linear latitude, variation
+ a = Coordinate(FloatLongitude(-112.096234), FloatLatitude(41.147101));
+ b = Coordinate(FloatLongitude(-112.096606), FloatLatitude(41.147259));
+ c = Coordinate(FloatLongitude(-112.096419), FloatLatitude(41.147259));
+ result = coordinate_calculation::circleCenter(a, b, c);
+ BOOST_CHECK(result);
+ BOOST_CHECK_EQUAL(*result, Coordinate(FloatLongitude(-112.096512), FloatLatitude(41.146962)));
+
+ // Co-linear latitude, impossible to calculate
+ a = Coordinate(FloatLongitude(-112.096234), FloatLatitude(41.147259));
+ b = Coordinate(FloatLongitude(-112.096606), FloatLatitude(41.147259));
+ c = Coordinate(FloatLongitude(-112.096419), FloatLatitude(41.147259));
+ result = coordinate_calculation::circleCenter(a, b, c);
+ BOOST_CHECK(!result);
+}
+
BOOST_AUTO_TEST_SUITE_END()
diff --git a/unit_tests/util/rectangle.cpp b/unit_tests/util/rectangle.cpp
index f85d073..c68fbda 100644
--- a/unit_tests/util/rectangle.cpp
+++ b/unit_tests/util/rectangle.cpp
@@ -43,14 +43,14 @@ BOOST_AUTO_TEST_CASE(get_min_dist_test)
Coordinate nw_e{FloatLongitude(-9.9), FloatLatitude(45.0)};
Coordinate nw_w{FloatLongitude(-100.1), FloatLatitude(45.0)};
Coordinate nw_n{FloatLongitude(-55), FloatLatitude(80.1)};
- BOOST_CHECK_CLOSE(nw.GetMinSquaredDist(nw_sw), 0.02, 0.1);
- BOOST_CHECK_CLOSE(nw.GetMinSquaredDist(nw_se), 0.02, 0.1);
- BOOST_CHECK_CLOSE(nw.GetMinSquaredDist(nw_ne), 0.02, 0.1);
- BOOST_CHECK_CLOSE(nw.GetMinSquaredDist(nw_nw), 0.02, 0.1);
- BOOST_CHECK_CLOSE(nw.GetMinSquaredDist(nw_s), 0.01, 0.1);
- BOOST_CHECK_CLOSE(nw.GetMinSquaredDist(nw_e), 0.01, 0.1);
- BOOST_CHECK_CLOSE(nw.GetMinSquaredDist(nw_w), 0.01, 0.1);
- BOOST_CHECK_CLOSE(nw.GetMinSquaredDist(nw_n), 0.01, 0.1);
+ BOOST_CHECK_CLOSE(nw.GetMinSquaredDist(nw_sw), 0.02 * COORDINATE_PRECISION * COORDINATE_PRECISION, 0.1);
+ BOOST_CHECK_CLOSE(nw.GetMinSquaredDist(nw_se), 0.02 * COORDINATE_PRECISION * COORDINATE_PRECISION, 0.1);
+ BOOST_CHECK_CLOSE(nw.GetMinSquaredDist(nw_ne), 0.02 * COORDINATE_PRECISION * COORDINATE_PRECISION, 0.1);
+ BOOST_CHECK_CLOSE(nw.GetMinSquaredDist(nw_nw), 0.02 * COORDINATE_PRECISION * COORDINATE_PRECISION, 0.1);
+ BOOST_CHECK_CLOSE(nw.GetMinSquaredDist(nw_s), 0.01 * COORDINATE_PRECISION * COORDINATE_PRECISION, 0.1);
+ BOOST_CHECK_CLOSE(nw.GetMinSquaredDist(nw_e), 0.01 * COORDINATE_PRECISION * COORDINATE_PRECISION, 0.1);
+ BOOST_CHECK_CLOSE(nw.GetMinSquaredDist(nw_w), 0.01 * COORDINATE_PRECISION * COORDINATE_PRECISION, 0.1);
+ BOOST_CHECK_CLOSE(nw.GetMinSquaredDist(nw_n), 0.01 * COORDINATE_PRECISION * COORDINATE_PRECISION, 0.1);
Coordinate ne_sw{FloatLongitude(9.9), FloatLatitude(9.9)};
Coordinate ne_se{FloatLongitude(100.1), FloatLatitude(9.9)};
@@ -60,14 +60,14 @@ BOOST_AUTO_TEST_CASE(get_min_dist_test)
Coordinate ne_e{FloatLongitude(100.1), FloatLatitude(45.0)};
Coordinate ne_w{FloatLongitude(9.9), FloatLatitude(45.0)};
Coordinate ne_n{FloatLongitude(55), FloatLatitude(80.1)};
- BOOST_CHECK_CLOSE(ne.GetMinSquaredDist(ne_sw), 0.02, 0.1);
- BOOST_CHECK_CLOSE(ne.GetMinSquaredDist(ne_se), 0.02, 0.1);
- BOOST_CHECK_CLOSE(ne.GetMinSquaredDist(ne_ne), 0.02, 0.1);
- BOOST_CHECK_CLOSE(ne.GetMinSquaredDist(ne_nw), 0.02, 0.1);
- BOOST_CHECK_CLOSE(ne.GetMinSquaredDist(ne_s), 0.01, 0.1);
- BOOST_CHECK_CLOSE(ne.GetMinSquaredDist(ne_e), 0.01, 0.1);
- BOOST_CHECK_CLOSE(ne.GetMinSquaredDist(ne_w), 0.01, 0.1);
- BOOST_CHECK_CLOSE(ne.GetMinSquaredDist(ne_n), 0.01, 0.1);
+ BOOST_CHECK_CLOSE(ne.GetMinSquaredDist(ne_sw), 0.02 * COORDINATE_PRECISION * COORDINATE_PRECISION, 0.1);
+ BOOST_CHECK_CLOSE(ne.GetMinSquaredDist(ne_se), 0.02 * COORDINATE_PRECISION * COORDINATE_PRECISION, 0.1);
+ BOOST_CHECK_CLOSE(ne.GetMinSquaredDist(ne_ne), 0.02 * COORDINATE_PRECISION * COORDINATE_PRECISION, 0.1);
+ BOOST_CHECK_CLOSE(ne.GetMinSquaredDist(ne_nw), 0.02 * COORDINATE_PRECISION * COORDINATE_PRECISION, 0.1);
+ BOOST_CHECK_CLOSE(ne.GetMinSquaredDist(ne_s), 0.01 * COORDINATE_PRECISION * COORDINATE_PRECISION, 0.1);
+ BOOST_CHECK_CLOSE(ne.GetMinSquaredDist(ne_e), 0.01 * COORDINATE_PRECISION * COORDINATE_PRECISION, 0.1);
+ BOOST_CHECK_CLOSE(ne.GetMinSquaredDist(ne_w), 0.01 * COORDINATE_PRECISION * COORDINATE_PRECISION, 0.1);
+ BOOST_CHECK_CLOSE(ne.GetMinSquaredDist(ne_n), 0.01 * COORDINATE_PRECISION * COORDINATE_PRECISION, 0.1);
Coordinate se_ne{FloatLongitude(100.1), FloatLatitude(-9.9)};
Coordinate se_nw{FloatLongitude(9.9), FloatLatitude(-9.9)};
@@ -77,14 +77,14 @@ BOOST_AUTO_TEST_CASE(get_min_dist_test)
Coordinate se_w{FloatLongitude(9.9), FloatLatitude(-45.0)};
Coordinate se_e{FloatLongitude(100.1), FloatLatitude(-45.0)};
Coordinate se_s{FloatLongitude(55), FloatLatitude(-80.1)};
- BOOST_CHECK_CLOSE(se.GetMinSquaredDist(se_sw), 0.02, 0.1);
- BOOST_CHECK_CLOSE(se.GetMinSquaredDist(se_se), 0.02, 0.1);
- BOOST_CHECK_CLOSE(se.GetMinSquaredDist(se_ne), 0.02, 0.1);
- BOOST_CHECK_CLOSE(se.GetMinSquaredDist(se_nw), 0.02, 0.1);
- BOOST_CHECK_CLOSE(se.GetMinSquaredDist(se_s), 0.01, 0.1);
- BOOST_CHECK_CLOSE(se.GetMinSquaredDist(se_e), 0.01, 0.1);
- BOOST_CHECK_CLOSE(se.GetMinSquaredDist(se_w), 0.01, 0.1);
- BOOST_CHECK_CLOSE(se.GetMinSquaredDist(se_n), 0.01, 0.1);
+ BOOST_CHECK_CLOSE(se.GetMinSquaredDist(se_sw), 0.02 * COORDINATE_PRECISION * COORDINATE_PRECISION, 0.1);
+ BOOST_CHECK_CLOSE(se.GetMinSquaredDist(se_se), 0.02 * COORDINATE_PRECISION * COORDINATE_PRECISION, 0.1);
+ BOOST_CHECK_CLOSE(se.GetMinSquaredDist(se_ne), 0.02 * COORDINATE_PRECISION * COORDINATE_PRECISION, 0.1);
+ BOOST_CHECK_CLOSE(se.GetMinSquaredDist(se_nw), 0.02 * COORDINATE_PRECISION * COORDINATE_PRECISION, 0.1);
+ BOOST_CHECK_CLOSE(se.GetMinSquaredDist(se_s), 0.01 * COORDINATE_PRECISION * COORDINATE_PRECISION, 0.1);
+ BOOST_CHECK_CLOSE(se.GetMinSquaredDist(se_e), 0.01 * COORDINATE_PRECISION * COORDINATE_PRECISION, 0.1);
+ BOOST_CHECK_CLOSE(se.GetMinSquaredDist(se_w), 0.01 * COORDINATE_PRECISION * COORDINATE_PRECISION, 0.1);
+ BOOST_CHECK_CLOSE(se.GetMinSquaredDist(se_n), 0.01 * COORDINATE_PRECISION * COORDINATE_PRECISION, 0.1);
Coordinate sw_ne{FloatLongitude(-9.9), FloatLatitude(-9.9)};
Coordinate sw_nw{FloatLongitude(-100.1), FloatLatitude(-9.9)};
@@ -94,14 +94,14 @@ BOOST_AUTO_TEST_CASE(get_min_dist_test)
Coordinate sw_w{FloatLongitude(-100.1), FloatLatitude(-45.0)};
Coordinate sw_e{FloatLongitude(-9.9), FloatLatitude(-45.0)};
Coordinate sw_s{FloatLongitude(-55), FloatLatitude(-80.1)};
- BOOST_CHECK_CLOSE(sw.GetMinSquaredDist(sw_sw), 0.02, 0.1);
- BOOST_CHECK_CLOSE(sw.GetMinSquaredDist(sw_se), 0.02, 0.1);
- BOOST_CHECK_CLOSE(sw.GetMinSquaredDist(sw_ne), 0.02, 0.1);
- BOOST_CHECK_CLOSE(sw.GetMinSquaredDist(sw_nw), 0.02, 0.1);
- BOOST_CHECK_CLOSE(sw.GetMinSquaredDist(sw_s), 0.01, 0.1);
- BOOST_CHECK_CLOSE(sw.GetMinSquaredDist(sw_e), 0.01, 0.1);
- BOOST_CHECK_CLOSE(sw.GetMinSquaredDist(sw_w), 0.01, 0.1);
- BOOST_CHECK_CLOSE(sw.GetMinSquaredDist(sw_n), 0.01, 0.1);
+ BOOST_CHECK_CLOSE(sw.GetMinSquaredDist(sw_sw), 0.02 * COORDINATE_PRECISION * COORDINATE_PRECISION, 0.1);
+ BOOST_CHECK_CLOSE(sw.GetMinSquaredDist(sw_se), 0.02 * COORDINATE_PRECISION * COORDINATE_PRECISION, 0.1);
+ BOOST_CHECK_CLOSE(sw.GetMinSquaredDist(sw_ne), 0.02 * COORDINATE_PRECISION * COORDINATE_PRECISION, 0.1);
+ BOOST_CHECK_CLOSE(sw.GetMinSquaredDist(sw_nw), 0.02 * COORDINATE_PRECISION * COORDINATE_PRECISION, 0.1);
+ BOOST_CHECK_CLOSE(sw.GetMinSquaredDist(sw_s), 0.01 * COORDINATE_PRECISION * COORDINATE_PRECISION, 0.1);
+ BOOST_CHECK_CLOSE(sw.GetMinSquaredDist(sw_e), 0.01 * COORDINATE_PRECISION * COORDINATE_PRECISION, 0.1);
+ BOOST_CHECK_CLOSE(sw.GetMinSquaredDist(sw_w), 0.01 * COORDINATE_PRECISION * COORDINATE_PRECISION, 0.1);
+ BOOST_CHECK_CLOSE(sw.GetMinSquaredDist(sw_n), 0.01 * COORDINATE_PRECISION * COORDINATE_PRECISION, 0.1);
}
BOOST_AUTO_TEST_SUITE_END()
diff --git a/unit_tests/util/static_rtree.cpp b/unit_tests/util/static_rtree.cpp
index a9170be..b3c2c9e 100644
--- a/unit_tests/util/static_rtree.cpp
+++ b/unit_tests/util/static_rtree.cpp
@@ -1,28 +1,28 @@
-#include "extractor/edge_based_node.hpp"
#include "engine/geospatial_query.hpp"
-#include "util/typedefs.hpp"
-#include "util/rectangle.hpp"
-#include "util/exception.hpp"
-#include "util/coordinate_calculation.hpp"
+#include "extractor/edge_based_node.hpp"
#include "util/coordinate.hpp"
+#include "util/coordinate_calculation.hpp"
+#include "util/exception.hpp"
+#include "util/rectangle.hpp"
#include "util/static_rtree.hpp"
+#include "util/typedefs.hpp"
#include "mocks/mock_datafacade.hpp"
-#include <boost/test/unit_test.hpp>
+#include <boost/functional/hash.hpp>
#include <boost/test/auto_unit_test.hpp>
#include <boost/test/test_case_template.hpp>
-#include <boost/functional/hash.hpp>
+#include <boost/test/unit_test.hpp>
-#include <cstdint>
#include <cmath>
+#include <cstdint>
#include <algorithm>
#include <memory>
#include <random>
#include <string>
-#include <utility>
#include <unordered_set>
+#include <utility>
#include <vector>
BOOST_AUTO_TEST_SUITE(static_rtree)
@@ -62,10 +62,10 @@ template <typename DataT> class LinearSearchNN
{
std::vector<DataT> local_edges(edges);
- auto projected_input = coordinate_calculation::mercator::fromWGS84(input_coordinate);
- const auto segment_comparator = [this, &projected_input](const DataT &lhs, const DataT &rhs)
- {
- using coordinate_calculation::mercator::fromWGS84;
+ auto projected_input = web_mercator::fromWGS84(input_coordinate);
+ const auto segment_comparator = [this, &projected_input](const DataT &lhs,
+ const DataT &rhs) {
+ using web_mercator::fromWGS84;
const auto lhs_result = coordinate_calculation::projectPointOnSegment(
fromWGS84(coords->at(lhs.u)), fromWGS84(coords->at(lhs.v)), projected_input);
const auto rhs_result = coordinate_calculation::projectPointOnSegment(
@@ -230,13 +230,10 @@ void sampling_verify_rtree(RTreeT &rtree,
auto lsnn_u = result_lsnn.back().u;
auto lsnn_v = result_lsnn.back().v;
- Coordinate rtree_nearest;
- Coordinate lsnn_nearest;
- double ratio;
const double rtree_dist = coordinate_calculation::perpendicularDistance(
- coords[rtree_u], coords[rtree_v], q, rtree_nearest, ratio);
+ coords[rtree_u], coords[rtree_v], q);
const double lsnn_dist = coordinate_calculation::perpendicularDistance(
- coords[lsnn_u], coords[lsnn_v], q, lsnn_nearest, ratio);
+ coords[lsnn_u], coords[lsnn_v], q);
BOOST_CHECK_CLOSE(rtree_dist, lsnn_dist, 0.0001);
}
@@ -331,13 +328,6 @@ BOOST_AUTO_TEST_CASE(regression_test)
auto result_rtree = rtree.Nearest(input, 1);
auto result_ls = lsnn.Nearest(input, 1);
- auto distance_rtree = coordinate_calculation::perpendicularDistance(
- fixture.coords->at(result_rtree.front().u), fixture.coords->at(result_rtree.front().v),
- input);
-
- auto distance_lsnn = coordinate_calculation::perpendicularDistance(
- fixture.coords->at(result_ls.front().u), fixture.coords->at(result_ls.front().v), input);
-
BOOST_CHECK(result_rtree.size() == 1);
BOOST_CHECK(result_ls.size() == 1);
diff --git a/unit_tests/util/web_mercator.cpp b/unit_tests/util/web_mercator.cpp
new file mode 100644
index 0000000..7b00396
--- /dev/null
+++ b/unit_tests/util/web_mercator.cpp
@@ -0,0 +1,74 @@
+#include <boost/test/unit_test.hpp>
+
+#include "util/web_mercator.hpp"
+
+#include <osrm/coordinate.hpp>
+
+#include <cmath>
+
+using namespace osrm;
+using namespace osrm::util;
+
+BOOST_AUTO_TEST_SUITE(web_mercator_tests)
+
+BOOST_AUTO_TEST_CASE(lon_to_pixel)
+{
+ BOOST_CHECK_CLOSE(7.416042 * web_mercator::DEGREE_TO_PX, 825550.019142, 0.1);
+ BOOST_CHECK_CLOSE(7.415892 * web_mercator::DEGREE_TO_PX, 825533.321218, 0.1);
+ BOOST_CHECK_CLOSE(7.416016 * web_mercator::DEGREE_TO_PX, 825547.124835, 0.1);
+ BOOST_CHECK_CLOSE(7.41577 * web_mercator::DEGREE_TO_PX, 825519.74024, 0.1);
+ BOOST_CHECK_CLOSE(7.415808 * web_mercator::DEGREE_TO_PX, 825523.970381, 0.1);
+}
+
+BOOST_AUTO_TEST_CASE(lat_to_pixel)
+{
+ BOOST_CHECK_CLOSE(web_mercator::latToY(util::FloatLatitude(43.733947)) * web_mercator::DEGREE_TO_PX,
+ 5424361.75863, 0.1);
+ BOOST_CHECK_CLOSE(web_mercator::latToY(util::FloatLatitude(43.733799)) * web_mercator::DEGREE_TO_PX,
+ 5424338.95731, 0.1);
+ BOOST_CHECK_CLOSE(web_mercator::latToY(util::FloatLatitude(43.733922)) * web_mercator::DEGREE_TO_PX,
+ 5424357.90705, 0.1);
+ BOOST_CHECK_CLOSE(web_mercator::latToY(util::FloatLatitude(43.733697)) * web_mercator::DEGREE_TO_PX,
+ 5424323.24293, 0.1);
+ BOOST_CHECK_CLOSE(web_mercator::latToY(util::FloatLatitude(43.733729)) * web_mercator::DEGREE_TO_PX,
+ 5424328.17293, 0.1);
+}
+
+BOOST_AUTO_TEST_CASE(xyz_to_wgs84)
+{
+ double minx_1;
+ double miny_1;
+ double maxx_1;
+ double maxy_1;
+ web_mercator::xyzToWGS84(2, 2, 1, minx_1, miny_1, maxx_1, maxy_1);
+ BOOST_CHECK_CLOSE(minx_1, 180, 0.0001);
+ BOOST_CHECK_CLOSE(miny_1, -85.0511, 0.0001);
+ BOOST_CHECK_CLOSE(maxx_1, 360, 0.0001);
+ BOOST_CHECK_CLOSE(maxy_1, -85.0511, 0.0001);
+
+ double minx_2;
+ double miny_2;
+ double maxx_2;
+ double maxy_2;
+ web_mercator::xyzToWGS84(100, 0, 13, minx_2, miny_2, maxx_2, maxy_2);
+ BOOST_CHECK_CLOSE(minx_2, -175.6054, 0.0001);
+ BOOST_CHECK_CLOSE(miny_2, 85.0473, 0.0001);
+ BOOST_CHECK_CLOSE(maxx_2, -175.5615, 0.0001);
+ BOOST_CHECK_CLOSE(maxy_2, 85.0511, 0.0001);
+}
+
+BOOST_AUTO_TEST_CASE(xyz_to_mercator)
+{
+ double minx;
+ double miny;
+ double maxx;
+ double maxy;
+ web_mercator::xyzToMercator(100, 0, 13, minx, miny, maxx, maxy);
+
+ BOOST_CHECK_CLOSE(minx, -19548311.361764118075, 0.0001);
+ BOOST_CHECK_CLOSE(miny, 19971868.8804085782, 0.0001);
+ BOOST_CHECK_CLOSE(maxx, -19543419.391953866929, 0.0001);
+ BOOST_CHECK_CLOSE(maxy, 19971868.880408578, 0.0001);
+}
+
+BOOST_AUTO_TEST_SUITE_END()
--
Alioth's /usr/local/bin/git-commit-notice on /srv/git.debian.org/git/pkg-grass/osrm.git
More information about the Pkg-grass-devel
mailing list