Compare commits
62 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
| c8c3a49fb5 | |||
| 3ae313d35d | |||
| 9fca6987c9 | |||
| 7361558c19 | |||
| 834890cf0b | |||
| a53794f864 | |||
| 8fa98ed27d | |||
| 111030864c | |||
| 90e361c3dc | |||
| 32e6ccb037 | |||
| 258fcd8626 | |||
| 92c4a228e1 | |||
| 9eae1de9bc | |||
| 76f793533a | |||
| ec7e58e10e | |||
| ac5e095d17 | |||
| ee7912f882 | |||
| f460a9f17e | |||
| 37685dae73 | |||
| 5b58445535 | |||
| 5b79640b44 | |||
| 921471a153 | |||
| 3a1bf2c85d | |||
| 9b83649a03 | |||
| 2224389fb3 | |||
| aed7bd852d | |||
| c5b48e3506 | |||
| 73f4e1d45a | |||
| 002da129c8 | |||
| 1b545fee8a | |||
| cbc96ec492 | |||
| c95d845876 | |||
| ac7705e9a0 | |||
| 0b6eb85106 | |||
| e197dae54d | |||
| 4bf3c97476 | |||
| 19d2e82d15 | |||
| eb48945807 | |||
| a68db86dc8 | |||
| 948025440f | |||
| 8365e20d4f | |||
| 0fc6903d7e | |||
| 23fd27422b | |||
| e965cf12f8 | |||
| 523be8f7e5 | |||
| c2a605a70d | |||
| 910ee0829f | |||
| 704cf314d4 | |||
| b8651bfac9 | |||
| bf28e40ba6 | |||
| a8de007d98 | |||
| 4684d2e35c | |||
| 27a9603b98 | |||
| 1610ea8dee | |||
| 171ff1191f | |||
| b5f9ba63d5 | |||
| a3c0f6a4e2 | |||
| 963c042b2a | |||
| 1be7dedda7 | |||
| 493a9a1cb2 | |||
| e1149bd4b7 | |||
| 895f072425 |
@@ -0,0 +1,2 @@
|
||||
test
|
||||
build
|
||||
+48
@@ -285,6 +285,54 @@ matrix:
|
||||
after_success:
|
||||
- ./scripts/travis/publish.sh
|
||||
|
||||
- os: linux
|
||||
sudo: false
|
||||
compiler: "node-8-mason-linux-release"
|
||||
addons:
|
||||
apt:
|
||||
sources: ['ubuntu-toolchain-r-test']
|
||||
packages: ['libstdc++-4.9-dev']
|
||||
env: CLANG_VERSION='4.0.0' BUILD_TYPE='Release' ENABLE_MASON=ON ENABLE_LTO=ON JOBS=3 NODE="8"
|
||||
install:
|
||||
- pushd ${OSRM_BUILD_DIR}
|
||||
- |
|
||||
cmake .. -DCMAKE_BUILD_TYPE=${BUILD_TYPE} \
|
||||
-DENABLE_MASON=${ENABLE_MASON:-OFF} \
|
||||
-DENABLE_NODE_BINDINGS=${ENABLE_NODE_BINDINGS:-OFF} \
|
||||
-DENABLE_CCACHE=ON \
|
||||
-DCMAKE_INSTALL_PREFIX=${OSRM_INSTALL_DIR} \
|
||||
-DENABLE_GLIBC_WORKAROUND=ON
|
||||
- make --jobs=${JOBS}
|
||||
- popd
|
||||
script:
|
||||
- npm run nodejs-tests
|
||||
after_success:
|
||||
- ./scripts/travis/publish.sh
|
||||
|
||||
- os: linux
|
||||
sudo: false
|
||||
compiler: "node-6-mason-linux-release"
|
||||
addons:
|
||||
apt:
|
||||
sources: ['ubuntu-toolchain-r-test']
|
||||
packages: ['libstdc++-4.9-dev']
|
||||
env: CLANG_VERSION='4.0.0' BUILD_TYPE='Debug' ENABLE_MASON=ON ENABLE_LTO=ON JOBS=3 NODE="8"
|
||||
install:
|
||||
- pushd ${OSRM_BUILD_DIR}
|
||||
- |
|
||||
cmake .. -DCMAKE_BUILD_TYPE=${BUILD_TYPE} \
|
||||
-DENABLE_MASON=${ENABLE_MASON:-OFF} \
|
||||
-DENABLE_NODE_BINDINGS=${ENABLE_NODE_BINDINGS:-OFF} \
|
||||
-DENABLE_CCACHE=ON \
|
||||
-DCMAKE_INSTALL_PREFIX=${OSRM_INSTALL_DIR} \
|
||||
-DENABLE_GLIBC_WORKAROUND=ON
|
||||
- make --jobs=${JOBS}
|
||||
- popd
|
||||
script:
|
||||
- npm run nodejs-tests
|
||||
after_success:
|
||||
- ./scripts/travis/publish.sh
|
||||
|
||||
before_install:
|
||||
- source $NVM_DIR/nvm.sh
|
||||
- nvm install $NODE
|
||||
|
||||
+37
-2
@@ -1,15 +1,50 @@
|
||||
# 5.13.0 RC1
|
||||
# 5.14.0
|
||||
- Changes from 5.13
|
||||
- API:
|
||||
- ADDED: new RouteStep property `driving_side` that has either "left" or "right" for that step
|
||||
- Misc:
|
||||
- ADDED: Bundles a rough (please improve!) driving-side GeoJSON file for use with `osrm-extract --location-dependent-data data/driving_side.geojson`
|
||||
- CHANGED: Conditional turn parsing is disabled by default now
|
||||
- ADDED: Adds a tool to analyze turn instruction generation in a dataset. Useful for tracking turn-by-turn heuristic changes over time.
|
||||
- CHANGED: Internal refactoring of guidance code as a first step towards a re-runnable guidance pipeline
|
||||
- ADDED: Now publishing Node 8.x LTS binary modules
|
||||
- Profile:
|
||||
- CHANGED: Remove dependency on turn types and turn modifier in the process_turn function in the `car.lua` profile. Guidance instruction types are not used to influence turn penalty anymore so this will break backward compatibility between profile version 3 and 4.
|
||||
- Guidance:
|
||||
- ADDED: New internal flag on "segregated intersections" - in the future, will should allow collapsing of instructions across complex intersection geometry where humans only perceive a single maneuver
|
||||
- CHANGED: Decrease roundabout turn radius threshold from 25m to 15m - adds some "exit the roundabout" instructions for moderately sized roundabouts that were being missed previously
|
||||
- Docker:
|
||||
- CHANGED: switch to alpine 3.6, and use a multistage build to reduce image size
|
||||
- Build:
|
||||
- FIX: use LUA_LIBRARY_DIRS to propertly detect Lua on all platforms
|
||||
- Docs:
|
||||
- FIX: clarify description of roundabout exit instructions
|
||||
- Bugfixes:
|
||||
- FIXED: Fix bug where merge instructions got the wrong direction modifier ([PR #4670](https://github.com/Project-OSRM/osrm-backend/pull/4670))
|
||||
- FIXED: Properly use the `profile.properties.left_hand_driving` property, there was a typo that meant it had no effect
|
||||
- FIXED: undefined behaviour when alternative candidate via node is same as source node ([#4691](https://github.com/Project-OSRM/osrm-backend/issues/4691))
|
||||
- FIXED: ensure libosrm.pc is pushed to the correct location for pkgconfig to find it on all platforms
|
||||
- FIXED: don't consider empty names + empty refs as a valid name for u-turns
|
||||
|
||||
# 5.13.0
|
||||
- Changes from 5.12:
|
||||
- Profile:
|
||||
- Append cardinal directions from route relations to ref fields to improve instructions
|
||||
- Append cardinal directions from route relations to ref fields to improve instructions; off by default see `profile.cardinal_directions`
|
||||
- Support of `distance` weight in foot and bicycle profiles
|
||||
- Support of relations processing
|
||||
- Added `way:get_location_tag(key)` method to get location-dependent tags https://github.com/Project-OSRM/osrm-backend/wiki/Using-location-dependent-data-in-profiles
|
||||
- Added `forward_ref` and `backward_ref` support
|
||||
- Left-side driving mode is specified by a local Boolean flag `is_left_hand_driving` in `ExtractionWay` and `ExtractionTurn`
|
||||
- Support literal values for maxspeeds in NO, PL and ZA
|
||||
- Infrastructure:
|
||||
- Lua 5.1 support is removed due to lack of support in sol2 https://github.com/ThePhD/sol2/issues/302
|
||||
- Fixed pkg-config version of OSRM
|
||||
- Removed `.osrm.core` file since CoreCH is deprecated now.
|
||||
- Tools:
|
||||
- Because of boost/program_options#32 with boost 1.65+ we needed to change the behavior of the following flags to not accept `={true|false}` anymore:
|
||||
- `--use-locations-cache=false` becomes `--disable-location-cache`
|
||||
- `--parse-conditional-restrictions=true` becomes `--parse-conditional-restrictions`
|
||||
- The deprecated options `--use-level-cache` and `--generate-edge-lookup`
|
||||
- Bugfixes:
|
||||
- Fixed #4348: Some cases of sliproads pre-processing were broken
|
||||
- Fixed #4331: Correctly compute left/right modifiers of forks in case the fork is curved.
|
||||
|
||||
+2
-2
@@ -61,7 +61,7 @@ if (POLICY CMP0048)
|
||||
endif()
|
||||
project(OSRM C CXX)
|
||||
set(OSRM_VERSION_MAJOR 5)
|
||||
set(OSRM_VERSION_MINOR 13)
|
||||
set(OSRM_VERSION_MINOR 14)
|
||||
set(OSRM_VERSION_PATCH 0)
|
||||
set(OSRM_VERSION "${OSRM_VERSION_MAJOR}.${OSRM_VERSION_MINOR}.${OSRM_VERSION_PATCH}")
|
||||
|
||||
@@ -796,7 +796,7 @@ JOIN("-I${DEPENDENCIES_INCLUDE_DIRS}" " -I" PKGCONFIG_OSRM_INCLUDE_FLAGS)
|
||||
JOIN("${ENGINE_LIBRARIES}" " " PKGCONFIG_OSRM_DEPENDENT_LIBRARIES)
|
||||
|
||||
configure_file(${CMAKE_CURRENT_SOURCE_DIR}/cmake/pkgconfig.in libosrm.pc @ONLY)
|
||||
install(FILES ${PROJECT_BINARY_DIR}/libosrm.pc DESTINATION ${CMAKE_INSTALL_LIBDIR}/pkgconfig)
|
||||
install(FILES ${PROJECT_BINARY_DIR}/libosrm.pc DESTINATION ${PKGCONFIG_LIBRARY_DIR}/pkgconfig)
|
||||
|
||||
# uninstall target
|
||||
configure_file(
|
||||
|
||||
@@ -0,0 +1,3 @@
|
||||
# Code of conduct
|
||||
|
||||
Everyone is invited to participate in Project OSRM’s open source projects and public discussions: we want to create a welcoming and friendly environment. Harassment of participants or other unethical and unprofessional behavior will not be tolerated in our spaces. The [Contributor Covenant](http://contributor-covenant.org) applies to all projects under the Project-OSRM organization and we ask that you please read [the full text](http://contributor-covenant.org/version/1/2/0/).
|
||||
+5
-1
@@ -1,8 +1,12 @@
|
||||
# Everyone
|
||||
|
||||
Please take some time to review our [code of conduct](CODE_OF_CONDUCT.md) to help guide your interactions with others on this project.
|
||||
|
||||
# User
|
||||
|
||||
Before you open a new issue, please search for older ones that cover the same issue.
|
||||
In general "me too" comments/issues are frowned upon.
|
||||
You can add a :+1: emoji to the issue if you want to express interest in this.
|
||||
You can add a :+1: emoji reaction to the issue if you want to express interest in this.
|
||||
|
||||
# Developer
|
||||
|
||||
|
||||
@@ -19,7 +19,6 @@ To quickly try OSRM use our [demo server](http://map.project-osrm.org) which com
|
||||
For a quick introduction about how the road network is represented in OpenStreetMap and how to map specific road network features have a look at [this guide about mapping for navigation](https://www.mapbox.com/mapping/mapping-for-navigation/).
|
||||
|
||||
Related [Project-OSRM](https://github.com/Project-OSRM) repositories:
|
||||
- [node-osrm](https://www.npmjs.com/package/osrm) - Production-ready NodeJs bindings for the routing engine
|
||||
- [osrm-frontend](https://github.com/Project-OSRM/osrm-frontend) - User-facing frontend with map. The demo server runs this on top of the backend
|
||||
- [osrm-text-instructions](https://github.com/Project-OSRM/osrm-text-instructions) - Text instructions from OSRM route response
|
||||
- [osrm-backend-docker](https://hub.docker.com/r/osrm/osrm-backend/) - Ready to use Docker images
|
||||
|
||||
@@ -84,11 +84,15 @@ function(_lua_set_version_vars)
|
||||
lua.${CMAKE_MATCH_1}.${CMAKE_MATCH_2}
|
||||
)
|
||||
pkg_check_modules(LUA QUIET "lua${ver}")
|
||||
list(APPEND _lua_include_subdirs ${LUA_INCLUDE_DIRS})
|
||||
list(APPEND _lua_library_names ${LUA_LIBRARIES})
|
||||
list(APPEND _lua_library_dirs ${LUA_LIBRARY_DIRS})
|
||||
endforeach ()
|
||||
|
||||
set(_lua_include_subdirs "${_lua_include_subdirs}" PARENT_SCOPE)
|
||||
set(_lua_library_names "${_lua_library_names}" PARENT_SCOPE)
|
||||
set(_lua_append_versions "${_lua_append_versions}" PARENT_SCOPE)
|
||||
set(_lua_library_dirs "${_lua_library_dirs}" PARENT_SCOPE)
|
||||
endfunction(_lua_set_version_vars)
|
||||
|
||||
function(_lua_check_header_version _hdr_file)
|
||||
@@ -161,6 +165,7 @@ find_library(LUA_LIBRARY
|
||||
ENV LUA_DIR
|
||||
PATH_SUFFIXES lib
|
||||
PATHS
|
||||
${_lua_library_dirs}
|
||||
~/Library/Frameworks
|
||||
/Library/Frameworks
|
||||
/sw
|
||||
|
||||
+2
-2
@@ -1,6 +1,6 @@
|
||||
module.exports = {
|
||||
default: '--strict --tags ~@stress --tags ~@todo --require features/support --require features/step_definitions',
|
||||
verify: '--strict --tags ~@stress --tags ~@todo -f progress --require features/support --require features/step_definitions',
|
||||
default: '--strict --tags ~@stress --tags ~@todo --tags ~@mld-only --require features/support --require features/step_definitions',
|
||||
verify: '--strict --tags ~@stress --tags ~@todo --tags ~@mld-only -f progress --require features/support --require features/step_definitions',
|
||||
todo: '--strict --tags @todo --require features/support --require features/step_definitions',
|
||||
all: '--strict --require features/support --require features/step_definitions',
|
||||
mld: '--strict --tags ~@stress --tags ~@todo --require features/support --require features/step_definitions -f progress'
|
||||
|
||||
File diff suppressed because it is too large
Load Diff
+20
-28
@@ -1,34 +1,20 @@
|
||||
FROM alpine:3.5
|
||||
FROM alpine:3.6 as buildstage
|
||||
|
||||
RUN mkdir /opt
|
||||
WORKDIR /opt
|
||||
ARG DOCKER_TAG
|
||||
RUN mkdir -p /src && mkdir -p /opt
|
||||
COPY . /src
|
||||
WORKDIR /src
|
||||
|
||||
RUN NPROC=$(grep -c ^processor /proc/cpuinfo 2>/dev/null || 1) && \
|
||||
echo "@testing http://dl-cdn.alpinelinux.org/alpine/edge/testing" >> /etc/apk/repositories && \
|
||||
apk update && \
|
||||
apk upgrade && \
|
||||
apk add git cmake wget make libc-dev gcc g++ bzip2-dev boost-dev zlib-dev expat-dev lua5.2-dev libtbb@testing libtbb-dev@testing && \
|
||||
\
|
||||
echo "Building libstxxl" && \
|
||||
cd /opt && \
|
||||
git clone --depth 1 --branch 1.4.1 https://github.com/stxxl/stxxl.git && \
|
||||
cd stxxl && \
|
||||
mkdir build && \
|
||||
cd build && \
|
||||
cmake -DCMAKE_BUILD_TYPE=Release .. && \
|
||||
make -j${NPROC} && \
|
||||
make install
|
||||
|
||||
ARG DOCKER_TAG
|
||||
RUN mkdir /src
|
||||
COPY . /src
|
||||
WORKDIR /src
|
||||
|
||||
RUN NPROC=$(grep -c ^processor /proc/cpuinfo 2>/dev/null || 1) && \
|
||||
NPROC=$(grep -c ^processor /proc/cpuinfo 2>/dev/null || 1) && \
|
||||
echo "Building OSRM ${DOCKER_TAG}" && \
|
||||
git show --format="%H" | head -n1 > /opt/OSRM_GITSHA && \
|
||||
echo "Building OSRM gitsha $(cat /opt/OSRM_GITSHA)" && \
|
||||
mkdir build && \
|
||||
mkdir -p build && \
|
||||
cd build && \
|
||||
BUILD_TYPE="Release" && \
|
||||
ENABLE_ASSERTIONS="Off" && \
|
||||
@@ -41,13 +27,19 @@ RUN NPROC=$(grep -c ^processor /proc/cpuinfo 2>/dev/null || 1) && \
|
||||
cd ../profiles && \
|
||||
cp -r * /opt && \
|
||||
\
|
||||
echo "Cleaning up" && \
|
||||
strip /usr/local/bin/* && \
|
||||
rm /usr/local/lib/libstxxl* && \
|
||||
cd /opt && \
|
||||
apk del boost-dev && \
|
||||
apk del g++ cmake libc-dev expat-dev zlib-dev bzip2-dev lua5.2-dev git make gcc && \
|
||||
apk add boost-filesystem boost-program_options boost-regex boost-iostreams boost-thread libgomp lua5.2 expat && \
|
||||
rm -rf /src /opt/stxxl /usr/local/bin/stxxl_tool /usr/local/lib/libosrm*
|
||||
rm -rf /src /usr/local/lib/libosrm*
|
||||
|
||||
|
||||
# Multistage build to reduce image size - https://docs.docker.com/engine/userguide/eng-image/multistage-build/#use-multi-stage-builds
|
||||
# Only the content below ends up in the image, this helps remove /src from the image (which is large)
|
||||
FROM alpine:3.6 as runstage
|
||||
RUN mkdir -p /src && mkdir -p /opt
|
||||
RUN echo "@testing http://dl-cdn.alpinelinux.org/alpine/edge/testing" >> /etc/apk/repositories && \
|
||||
apk update && \
|
||||
apk add boost-filesystem boost-program_options boost-regex boost-iostreams boost-thread libgomp lua5.2 expat libtbb@testing
|
||||
COPY --from=buildstage /usr/local /usr/local
|
||||
COPY --from=buildstage /opt /opt
|
||||
WORKDIR /opt
|
||||
|
||||
EXPOSE 5000
|
||||
|
||||
+2
-1
@@ -594,6 +594,7 @@ step.
|
||||
- `intersections`: A list of `Intersection` objects that are passed along the segment, the very first belonging to the StepManeuver
|
||||
- `rotary_name`: The name for the rotary. Optionally included, if the step is a rotary and a rotary name is available.
|
||||
- `rotary_pronunciation`: The pronunciation hint of the rotary name. Optionally included, if the step is a rotary and a rotary pronunciation is available.
|
||||
- `driving_side`: The legal driving side at the location for this step. Either `left` or `right`.
|
||||
|
||||
#### Example
|
||||
|
||||
@@ -664,7 +665,7 @@ step.
|
||||
| `end of road` | road ends in a T intersection turn in direction of `modifier`|
|
||||
| `use lane` | **Deprecated** replaced by lanes on all intersection entries |
|
||||
| `continue` | Turn in direction of `modifier` to stay on the same road |
|
||||
| `roundabout` | traverse roundabout, has additional property `exit` with NR if the roundabout is left. The modifier specifies the direction of entering the roundabout. |
|
||||
| `roundabout` | traverse roundabout, if the route leaves the roundabout there will be an additional property `exit` for exit counting. The modifier specifies the direction of entering the roundabout. |
|
||||
| `rotary` | a traffic circle. While very similar to a larger version of a roundabout, it does not necessarily follow roundabout rules for right of way. It can offer `rotary_name` and/or `rotary_pronunciation` parameters (located in the RouteStep object) in addition to the `exit` parameter (located on the StepManeuver object). |
|
||||
| `roundabout turn`| Describes a turn at a small roundabout that should be treated as normal turn. The `modifier` indicates the turn direciton. Example instruction: `At the roundabout turn left`. |
|
||||
| `notification` | not an actual turn but a change in the driving conditions. For example the travel mode or classes. If the road takes a turn itself, the `modifier` describes the direction |
|
||||
|
||||
+3
-1
@@ -171,7 +171,9 @@ is_startpoint | Boolean | Can a journey start on this
|
||||
roundabout | Boolean | Is this part of a roundabout?
|
||||
circular | Boolean | Is this part of a non-roundabout circular junction?
|
||||
name | String | Name of the way
|
||||
ref | String | Road number
|
||||
ref | String | Road number (equal to set `forward_ref` and `backward_ref` with one value)
|
||||
forward_ref | String | Road number in forward way direction
|
||||
backward_ref | String | Road number in backward way direction
|
||||
destinations | String | The road's destinations
|
||||
exits | String | The ramp's exit numbers or names
|
||||
pronunciation | String | Name pronunciation
|
||||
|
||||
@@ -10,6 +10,7 @@ Feature: Barriers
|
||||
| | x |
|
||||
| bollard | x |
|
||||
| gate | x |
|
||||
| lift_gate | x |
|
||||
| cycle_barrier | x |
|
||||
| cattle_grid | x |
|
||||
| border_control | x |
|
||||
|
||||
@@ -157,15 +157,16 @@ Feature: Car - Restricted access
|
||||
|
||||
Scenario: Car - Access combinations
|
||||
Then routability should be
|
||||
| highway | access | vehicle | motor_vehicle | motorcar | forw | backw | # |
|
||||
| runway | private | | | permissive | x | x | |
|
||||
| primary | forestry | | yes | | x | x | |
|
||||
| cycleway | | | designated | | x | x | |
|
||||
| residential | | yes | no | | | | |
|
||||
| motorway | yes | permissive | | private | x | | implied oneway |
|
||||
| trunk | agricultural | designated | permissive | no | | | |
|
||||
| pedestrian | | | | | | | |
|
||||
| pedestrian | | | | destination | | | temporary disabled #3773 |
|
||||
| highway | access | vehicle | motor_vehicle | motorcar | forw | backw | # |
|
||||
| runway | private | | | permissive | x | x | |
|
||||
| primary | forestry | | yes | | x | x | |
|
||||
| cycleway | | | designated | | x | x | |
|
||||
| unclassified | | | destination | destination | x | x | |
|
||||
| residential | | yes | no | | | | |
|
||||
| motorway | yes | permissive | | private | x | | implied oneway |
|
||||
| trunk | agricultural | designated | permissive | no | | | |
|
||||
| pedestrian | | | | | | | |
|
||||
| pedestrian | | | | destination | | | temporary disabled #3773 |
|
||||
|
||||
Scenario: Car - Ignore access tags for other modes
|
||||
Then routability should be
|
||||
|
||||
+10
-10
@@ -20,9 +20,9 @@ Feature: Car - Handle driving
|
||||
| efg | primary | | |
|
||||
|
||||
When I route I should get
|
||||
| from | to | route | modes |
|
||||
| a | g | abc,cde,efg,efg | driving,driving,driving,driving |
|
||||
| e | a | cde,abc,abc | driving,driving,driving |
|
||||
| from | to | route | modes | turns |
|
||||
| a | g | abc,cde,efg,efg | driving,driving,driving,driving | depart,new name right,new name left,arrive |
|
||||
| e | a | cde,abc,abc | driving,driving,driving | depart,new name left,arrive |
|
||||
|
||||
Scenario: Car - Control test without durations, osrm uses movable bridge speed to calculate duration
|
||||
Given the node map
|
||||
@@ -39,9 +39,9 @@ Feature: Car - Handle driving
|
||||
| efg | primary | |
|
||||
|
||||
When I route I should get
|
||||
| from | to | route | modes | speed | time |
|
||||
| a | g | abc,cde,efg,efg | driving,driving,driving,driving | 13 km/h | 340s +-1 |
|
||||
| e | c | cde,cde | driving,driving | 5 km/h | 295s +-1 |
|
||||
| from | to | route | modes | speed | time | turns |
|
||||
| a | g | abc,cde,efg,efg | driving,driving,driving,driving | 13 km/h | 332s +-1 | depart,new name right,new name left,arrive |
|
||||
| e | c | cde,cde | driving,driving | 5 km/h | 288s +-1 | depart,arrive |
|
||||
|
||||
Scenario: Car - Properly handle durations
|
||||
Given the node map
|
||||
@@ -58,7 +58,7 @@ Feature: Car - Handle driving
|
||||
| efg | primary | | |
|
||||
|
||||
When I route I should get
|
||||
| from | to | route | modes | speed |
|
||||
| a | g | abc,cde,efg,efg | driving,driving,driving,driving | 7 km/h |
|
||||
| c | e | cde,cde | driving,driving | 2 km/h |
|
||||
| e | c | cde,cde | driving,driving | 2 km/h |
|
||||
| from | to | route | modes | speed | turns |
|
||||
| a | g | abc,cde,efg,efg | driving,driving,driving,driving | 7 km/h | depart,new name right,new name left,arrive |
|
||||
| c | e | cde,cde | driving,driving | 2 km/h | depart,arrive |
|
||||
| e | c | cde,cde | driving,driving | 2 km/h | depart,arrive |
|
||||
|
||||
@@ -677,7 +677,7 @@ Feature: Car - Turn restrictions
|
||||
# https://www.openstreetmap.org/#map=18/38.91099/-77.00888
|
||||
@no_turning @conditionals
|
||||
Scenario: Car - DC North capitol situation, two on one off
|
||||
Given the extract extra arguments "--parse-conditional-restrictions=1"
|
||||
Given the extract extra arguments "--parse-conditional-restrictions"
|
||||
# 9pm Wed 02 May, 2017 UTC, 5pm EDT
|
||||
Given the contract extra arguments "--time-zone-file=test/data/tz/{timezone_names}/dc.geojson --parse-conditionals-from-now=1493845200"
|
||||
Given the customize extra arguments "--time-zone-file=test/data/tz/{timezone_names}/dc.geojson --parse-conditionals-from-now=1493845200"
|
||||
@@ -724,7 +724,7 @@ Feature: Car - Turn restrictions
|
||||
|
||||
@no_turning @conditionals
|
||||
Scenario: Car - DC North capitol situation, one on two off
|
||||
Given the extract extra arguments "--parse-conditional-restrictions=1"
|
||||
Given the extract extra arguments "--parse-conditional-restrictions"
|
||||
# 10:30am utc, wed, 6:30am est
|
||||
Given the contract extra arguments "--time-zone-file=test/data/tz/{timezone_names}/dc.geojson --parse-conditionals-from-now=1493807400"
|
||||
Given the customize extra arguments "--time-zone-file=test/data/tz/{timezone_names}/dc.geojson --parse-conditionals-from-now=1493807400"
|
||||
@@ -848,7 +848,7 @@ Feature: Car - Turn restrictions
|
||||
|
||||
@only_turning @conditionals
|
||||
Scenario: Car - Somewhere in London, the UK, GMT timezone
|
||||
Given the extract extra arguments "--parse-conditional-restrictions=1"
|
||||
Given the extract extra arguments "--parse-conditional-restrictions"
|
||||
# 9am UTC, 10am BST
|
||||
Given the contract extra arguments "--time-zone-file=test/data/tz/{timezone_names}/london.geojson --parse-conditionals-from-now=1493802000"
|
||||
Given the customize extra arguments "--time-zone-file=test/data/tz/{timezone_names}/london.geojson --parse-conditionals-from-now=1493802000"
|
||||
|
||||
@@ -4,6 +4,11 @@ Feature: Car - route relations
|
||||
Given the profile "car"
|
||||
|
||||
Scenario: Assignment using relation membership roles
|
||||
Given the profile file "car" initialized with
|
||||
"""
|
||||
profile.cardinal_directions = true
|
||||
"""
|
||||
|
||||
Given the node map
|
||||
"""
|
||||
a----------------b
|
||||
@@ -26,7 +31,63 @@ Feature: Car - route relations
|
||||
| b,a | westbound,westbound | I 80 $west,I 80 $west |
|
||||
| c,d | eastbound,eastbound | I 80 $east; CO 93 $east,I 80 $east; CO 93 $east |
|
||||
|
||||
Scenario: No cardinal directions by default
|
||||
Given the profile file "car" initialized with
|
||||
"""
|
||||
profile.cardinal_directions = false
|
||||
"""
|
||||
Given the node map
|
||||
"""
|
||||
a----------------b
|
||||
c----------------d
|
||||
"""
|
||||
|
||||
And the ways
|
||||
| nodes | name | highway | ref |
|
||||
| ba | westbound | motorway | I 80 |
|
||||
| cd | eastbound | motorway | I 80;CO 93 |
|
||||
|
||||
And the relations
|
||||
| type | way:east | way:west | route | ref | network |
|
||||
| route | cd | ba | road | 80 | US:I |
|
||||
| route | cd | ba | road | 93 | US:CO |
|
||||
|
||||
|
||||
When I route I should get
|
||||
| waypoints | route | ref |
|
||||
| b,a | westbound,westbound | I 80,I 80 |
|
||||
| c,d | eastbound,eastbound | I 80; CO 93,I 80; CO 93 |
|
||||
|
||||
Scenario: No cardinal directions by default
|
||||
Given the node map
|
||||
"""
|
||||
a----------------b
|
||||
c----------------d
|
||||
"""
|
||||
|
||||
And the ways
|
||||
| nodes | name | highway | ref |
|
||||
| ba | westbound | motorway | I 80 |
|
||||
| cd | eastbound | motorway | I 80;CO 93 |
|
||||
|
||||
And the relations
|
||||
| type | way:east | way:west | route | ref | network |
|
||||
| route | cd | ba | road | 80 | US:I |
|
||||
| route | cd | ba | road | 93 | US:CO |
|
||||
|
||||
|
||||
When I route I should get
|
||||
| waypoints | route | ref |
|
||||
| b,a | westbound,westbound | I 80,I 80 |
|
||||
| c,d | eastbound,eastbound | I 80; CO 93,I 80; CO 93 |
|
||||
|
||||
|
||||
Scenario: Assignment using relation direction property (no role on members)
|
||||
Given the profile file "car" initialized with
|
||||
"""
|
||||
profile.cardinal_directions = true
|
||||
"""
|
||||
|
||||
Given the node map
|
||||
"""
|
||||
a----------------b
|
||||
@@ -51,6 +112,11 @@ Feature: Car - route relations
|
||||
|
||||
|
||||
Scenario: Forward assignment on one-way roads using relation direction property
|
||||
Given the profile file "car" initialized with
|
||||
"""
|
||||
profile.cardinal_directions = true
|
||||
"""
|
||||
|
||||
Given the node map
|
||||
"""
|
||||
a----------------b
|
||||
@@ -74,31 +140,41 @@ Feature: Car - route relations
|
||||
| c,d | eastbound,eastbound | I 80 $east; CO 93 $east,I 80 $east; CO 93 $east |
|
||||
|
||||
|
||||
# Scenario: Forward/backward assignment on non-divided roads with role direction tag
|
||||
# Given the node map
|
||||
# """
|
||||
# a----------------b
|
||||
# """
|
||||
#
|
||||
# And the ways
|
||||
# | nodes | name | highway | ref | oneway |
|
||||
# | ab | mainroad | motorway | I 80 | no |
|
||||
#
|
||||
# And the relations
|
||||
# | type | direction | way:forward | route | ref | network |
|
||||
# | route | west | ab | road | 80 | US:I |
|
||||
#
|
||||
# And the relations
|
||||
# | type | direction | way:backward | route | ref | network |
|
||||
# | route | east | ab | road | 80 | US:I |
|
||||
#
|
||||
# When I route I should get
|
||||
# | waypoints | route | ref |
|
||||
# | b,a | mainroad,mainroad | I 80 $west,I 80 $west |
|
||||
# | a,b | mainroad,mainroad | I 80 $east,I 80 $east |
|
||||
Scenario: Forward/backward assignment on non-divided roads with role direction tag
|
||||
Given the profile file "car" initialized with
|
||||
"""
|
||||
profile.cardinal_directions = true
|
||||
"""
|
||||
|
||||
Given the node map
|
||||
"""
|
||||
a----------------b
|
||||
"""
|
||||
|
||||
And the ways
|
||||
| nodes | name | highway | ref | oneway |
|
||||
| ab | mainroad | motorway | I 80 | no |
|
||||
|
||||
And the relations
|
||||
| type | direction | way:forward | route | ref | network |
|
||||
| route | west | ab | road | 80 | US:I |
|
||||
|
||||
And the relations
|
||||
| type | direction | way:backward | route | ref | network |
|
||||
| route | east | ab | road | 80 | US:I |
|
||||
|
||||
When I route I should get
|
||||
| waypoints | route | ref |
|
||||
| a,b | mainroad,mainroad | I 80 $west,I 80 $west |
|
||||
| b,a | mainroad,mainroad | I 80 $east,I 80 $east |
|
||||
|
||||
|
||||
Scenario: Conflict between role and direction
|
||||
Given the profile file "car" initialized with
|
||||
"""
|
||||
profile.cardinal_directions = true
|
||||
"""
|
||||
|
||||
Given the node map
|
||||
"""
|
||||
a----------------b
|
||||
@@ -118,6 +194,11 @@ Feature: Car - route relations
|
||||
|
||||
|
||||
Scenario: Conflict between role and superrelation direction
|
||||
Given the profile file "car" initialized with
|
||||
"""
|
||||
profile.cardinal_directions = true
|
||||
"""
|
||||
|
||||
Given the node map
|
||||
"""
|
||||
a----------------b
|
||||
@@ -140,6 +221,11 @@ Feature: Car - route relations
|
||||
| a,b | eastbound,eastbound | I 80,I 80 |
|
||||
|
||||
Scenario: Conflict between role and superrelation role
|
||||
Given the profile file "car" initialized with
|
||||
"""
|
||||
profile.cardinal_directions = true
|
||||
"""
|
||||
|
||||
Given the node map
|
||||
"""
|
||||
a----------------b
|
||||
@@ -162,6 +248,11 @@ Feature: Car - route relations
|
||||
| a,b | eastbound,eastbound | I 80,I 80 |
|
||||
|
||||
Scenario: Direction only available via superrelation role
|
||||
Given the profile file "car" initialized with
|
||||
"""
|
||||
profile.cardinal_directions = true
|
||||
"""
|
||||
|
||||
Given the node map
|
||||
"""
|
||||
a----------------b
|
||||
@@ -184,6 +275,11 @@ Feature: Car - route relations
|
||||
| a,b | eastbound,eastbound | I 80 $east,I 80 $east |
|
||||
|
||||
Scenario: Direction only available via superrelation direction
|
||||
Given the profile file "car" initialized with
|
||||
"""
|
||||
profile.cardinal_directions = true
|
||||
"""
|
||||
|
||||
Given the node map
|
||||
"""
|
||||
a----------------b
|
||||
@@ -205,6 +301,7 @@ Feature: Car - route relations
|
||||
| waypoints | route | ref |
|
||||
| a,b | eastbound,eastbound | I 80 $east,I 80 $east |
|
||||
|
||||
|
||||
# Scenario: Three levels of indirection
|
||||
# Given the node map
|
||||
# """
|
||||
@@ -229,4 +326,4 @@ Feature: Car - route relations
|
||||
#
|
||||
# When I route I should get
|
||||
# | waypoints | route | ref |
|
||||
# | a,b | eastbound,eastbound | I 80 $east,I 80 $east |
|
||||
# | a,b | eastbound,eastbound | I 80 $east,I 80 $east |
|
||||
|
||||
@@ -4,7 +4,7 @@ Feature: Testbot - side bias
|
||||
Scenario: Left-hand bias
|
||||
Given the profile file "car" initialized with
|
||||
"""
|
||||
profile.left_hand_driving = true
|
||||
profile.properties.left_hand_driving = true
|
||||
profile.turn_bias = 1.075
|
||||
"""
|
||||
And the node map
|
||||
@@ -20,14 +20,14 @@ Feature: Testbot - side bias
|
||||
| bd |
|
||||
|
||||
When I route I should get
|
||||
| from | to | route | time |
|
||||
| d | a | bd,ab,ab | 24s +-1 |
|
||||
| d | c | bd,bc,bc | 27s +-1 |
|
||||
| from | to | route | time | driving_side |
|
||||
| d | a | bd,ab,ab | 24s +-1 | left,left,left |
|
||||
| d | c | bd,bc,bc | 27s +-1 | left,left,left |
|
||||
|
||||
Scenario: Right-hand bias
|
||||
Given the profile file "car" initialized with
|
||||
"""
|
||||
profile.left_hand_driving = true
|
||||
profile.properties.left_hand_driving = true
|
||||
profile.turn_bias = 1 / 1.075
|
||||
"""
|
||||
And the node map
|
||||
@@ -43,14 +43,14 @@ Feature: Testbot - side bias
|
||||
| bd |
|
||||
|
||||
When I route I should get
|
||||
| from | to | route | time | # |
|
||||
| d | a | bd,ab,ab | 27s +-1 | should be inverse of left hand bias |
|
||||
| d | c | bd,bc,bc | 24s +-1 | |
|
||||
| from | to | route | time | driving_side | # |
|
||||
| d | a | bd,ab,ab | 27s +-1 | left,left,left | should be inverse of left hand bias |
|
||||
| d | c | bd,bc,bc | 24s +-1 | left,left,left | |
|
||||
|
||||
Scenario: Roundabout exit counting for left sided driving
|
||||
Given the profile file "testbot" initialized with
|
||||
Given the profile file "car" initialized with
|
||||
"""
|
||||
profile.left_hand_driving = true
|
||||
profile.properties.left_hand_driving = true
|
||||
"""
|
||||
And a grid size of 10 meters
|
||||
And the node map
|
||||
@@ -70,10 +70,10 @@ Feature: Testbot - side bias
|
||||
| bcegb | roundabout |
|
||||
|
||||
When I route I should get
|
||||
| waypoints | route | turns |
|
||||
| a,d | ab,cd,cd | depart,roundabout turn left exit-1,arrive |
|
||||
| a,f | ab,ef,ef | depart,roundabout turn straight exit-2,arrive |
|
||||
| a,h | ab,gh,gh | depart,roundabout turn right exit-3,arrive |
|
||||
| waypoints | route | driving_side | turns |
|
||||
| a,d | ab,cd,cd | left,left,left | depart,roundabout turn left exit-1,arrive |
|
||||
| a,f | ab,ef,ef | left,left,left | depart,roundabout turn straight exit-2,arrive |
|
||||
| a,h | ab,gh,gh | left,left,left | depart,roundabout turn right exit-3,arrive |
|
||||
|
||||
|
||||
Scenario: Left-hand bias via location-dependent tags
|
||||
@@ -92,9 +92,9 @@ Feature: Testbot - side bias
|
||||
And the extract extra arguments "--location-dependent-data test/data/regions/null-island.geojson"
|
||||
|
||||
When I route I should get
|
||||
| from | to | route | time |
|
||||
| d | a | bd,ab,ab | 24s +-1 |
|
||||
| d | c | bd,bc,bc | 27s +-1 |
|
||||
| from | to | route | driving_side | time |
|
||||
| d | a | bd,ab,ab | left,left,left | 24s +-1 |
|
||||
| d | c | bd,bc,bc | left,left,left | 27s +-1 |
|
||||
|
||||
|
||||
Scenario: Left-hand bias via OSM tags
|
||||
@@ -113,6 +113,6 @@ Feature: Testbot - side bias
|
||||
And the extract extra arguments "--location-dependent-data test/data/regions/null-island.geojson"
|
||||
|
||||
When I route I should get
|
||||
| from | to | route | time |
|
||||
| d | a | bd,ab,ab | 27s +-1 |
|
||||
| d | c | bd,bc,bc | 24s +-1 |
|
||||
| from | to | route | driving_side | time |
|
||||
| d | a | bd,ab,ab | right,right,right | 27s +-1 |
|
||||
| d | c | bd,bc,bc | right,right,right | 24s +-1 |
|
||||
|
||||
@@ -6,9 +6,9 @@ Feature: Car - weights
|
||||
And the node map
|
||||
"""
|
||||
a--b--c
|
||||
|
|
||||
d
|
||||
|
|
||||
| |
|
||||
d |
|
||||
| |
|
||||
e--f--g
|
||||
"""
|
||||
And the ways
|
||||
@@ -19,7 +19,7 @@ Feature: Car - weights
|
||||
| bdf | service |
|
||||
When I route I should get
|
||||
| from | to | route | speed | weight |
|
||||
| a | e | abc,cg,efg,efg | 28 km/h | 126.6 |
|
||||
| a | e | abc,cg,efg,efg | 29 km/h | 122.4 |
|
||||
| a | d | abc,bdf,bdf | 18 km/h | 71.7 |
|
||||
|
||||
Scenario: Does not jump off the highway to go down service road
|
||||
@@ -59,7 +59,7 @@ Feature: Car - weights
|
||||
When I route I should get
|
||||
| from | to | route | speed | weight |
|
||||
| a | d | ab,bc,cd,cd | 65 km/h | 44.4 |
|
||||
| a | e | ab,be,be | 14 km/h | 112 |
|
||||
| a | e | ab,be,be | 14 km/h | 111.8 |
|
||||
|
||||
Scenario: Distance weights
|
||||
Given the profile file "car" initialized with
|
||||
|
||||
@@ -10,6 +10,7 @@ Feature: Barriers
|
||||
| | x |
|
||||
| bollard | x |
|
||||
| gate | x |
|
||||
| lift_gate | x |
|
||||
| cycle_barrier | x |
|
||||
| cattle_grid | x |
|
||||
| border_control | x |
|
||||
|
||||
@@ -47,7 +47,7 @@ Feature: Turn Lane Guidance
|
||||
e
|
||||
a . . b . . . c g
|
||||
` .
|
||||
` .
|
||||
` .
|
||||
` d
|
||||
f
|
||||
"""
|
||||
|
||||
@@ -50,6 +50,32 @@ Feature: Collapse
|
||||
| i,h | second,first,first | depart,turn left,arrive | i,f,h |
|
||||
| i,l | second,second,second | depart,continue uturn,arrive | i,f,l |
|
||||
|
||||
Scenario: Segregated Intersection, Cross Belonging to Single Street
|
||||
Given the node map
|
||||
"""
|
||||
g
|
||||
|
||||
c b a
|
||||
d e f
|
||||
|
||||
h i
|
||||
"""
|
||||
|
||||
And the ways
|
||||
| nodes | highway | name | oneway |
|
||||
| ab | primary | first | yes |
|
||||
| bc | primary | first | yes |
|
||||
| de | primary | first | yes |
|
||||
| ef | primary | first | yes |
|
||||
| gb | primary | second | no |
|
||||
| be | primary | second | no |
|
||||
| eh | primary | second | yes |
|
||||
| ei | primary | third | yes |
|
||||
|
||||
When I route I should get
|
||||
| waypoints | route | turns | locations |
|
||||
| a,i | first,second,third,third | depart,turn left,turn slight left,arrive | a,b,e,i |
|
||||
|
||||
Scenario: Segregated Intersection, Cross Belonging to Correct Street
|
||||
Given the node map
|
||||
"""
|
||||
@@ -1074,3 +1100,27 @@ Feature: Collapse
|
||||
When I route I should get
|
||||
| waypoints | bearings | route | turns | locations |
|
||||
| 1,2 | 90 270 | ab,bd,bd,ab,ab | depart,turn left,continue uturn,turn right,arrive | _,b,d,b,_ |
|
||||
|
||||
|
||||
# https://www.openstreetmap.org/#map=18/37.74844/-122.40275
|
||||
Scenario: Don't use destinations as names
|
||||
Given the node map
|
||||
"""
|
||||
f - - - - e - - - - d
|
||||
|
|
||||
|
|
||||
|
|
||||
|
|
||||
|
|
||||
a - - - - b - - - - c
|
||||
"""
|
||||
|
||||
And the ways
|
||||
| nodes | highway | name | oneway | destination:ref |
|
||||
| abc | residential | road | yes | |
|
||||
| def | motorway_link | | yes | US 101 |
|
||||
| be | residential | cross | no | |
|
||||
|
||||
When I route I should get
|
||||
| waypoints | route | turns |
|
||||
| a,f | road,cross,, | depart,turn left,on ramp left,arrive |
|
||||
|
||||
@@ -354,9 +354,9 @@ Feature: Merge Segregated Roads
|
||||
| hb | road | yes |
|
||||
|
||||
When I route I should get
|
||||
| waypoints | turns | route | intersections |
|
||||
| waypoints | turns | route | intersections |
|
||||
| a,f | depart,arrive | road,road | true:180,false:0 true:180,false:0 true:180;true:0 |
|
||||
| c,f | depart,arrive | bridge,road | true:180,false:0 true:180;true:0 |
|
||||
| c,f | depart,arrive | bridge,road | true:180,false:0 true:180;true:0 |
|
||||
| 1,f | depart,arrive | bridge,road | true:180,false:0 true:180;true:0 |
|
||||
| f,a | depart,arrive | road,road | true:0,true:0 false:180,true:0 false:180;true:180 |
|
||||
| g,a | depart,arrive | bridge,road | true:0,true:0 false:180;true:180 |
|
||||
@@ -518,35 +518,32 @@ Feature: Merge Segregated Roads
|
||||
|
||||
# the goal here should be not to mention the intersection in the middle at all and also suppress the segregated parts
|
||||
When I route I should get
|
||||
| waypoints | route | intersections |
|
||||
| waypoints | route | intersections |
|
||||
| a,l | horiz,vert,vert | true:90;false:0 true:60 true:90 true:180 false:270,true:60 false:120 false:240 false:300,true:0 false:90 false:180 false:240 true:270;true:180 |
|
||||
| a,d | horiz,horiz | true:90,false:0 true:60 true:90 true:180 false:270,false:0 true:90 false:180 false:270 true:300;true:270 |
|
||||
| a,d | horiz,horiz | true:90,false:0 true:60 true:90 true:180 false:270,false:0 true:90 false:180 false:270 true:300;true:270 |
|
||||
| j,h | vert,horiz,horiz | true:0;true:0 true:90 false:180 false:270 true:300,false:60 false:120 false:240 true:300,false:0 false:90 false:120 true:180 true:270;true:90 |
|
||||
| j,l | vert,vert | true:0,true:0 true:90 false:180 false:270 true:300,true:0 false:90 false:180 true:240 false:270;true:180 |
|
||||
| j,l | vert,vert | true:0,true:0 true:90 false:180 false:270 true:300,true:0 false:90 false:180 true:240 false:270;true:180 |
|
||||
|
||||
|
||||
Scenario: Square Area - Don't merge almost circular roads
|
||||
Given a grid size of 2 meters
|
||||
Given the node map
|
||||
"""
|
||||
i
|
||||
/
|
||||
/
|
||||
/
|
||||
b---- g .
|
||||
/ p .
|
||||
a / \ f
|
||||
\ / o /
|
||||
\ / \ /
|
||||
c n /
|
||||
/ \ \/
|
||||
/ k e
|
||||
/ \ /
|
||||
h l /
|
||||
i
|
||||
b `
|
||||
` ` p .
|
||||
a ` g` ` \ f
|
||||
\ / o /
|
||||
\ / \ /
|
||||
h - - c n /
|
||||
\ \/
|
||||
k e
|
||||
\ /
|
||||
l /
|
||||
\ /
|
||||
m . d
|
||||
/
|
||||
j
|
||||
/
|
||||
j
|
||||
"""
|
||||
|
||||
And the ways
|
||||
@@ -560,5 +557,144 @@ Feature: Merge Segregated Roads
|
||||
| jd | Hubertusallee | yes |
|
||||
|
||||
When I route I should get
|
||||
| waypoints | route | turns |
|
||||
| i,h | Kurfürstendamm,Hubertusallee,Hubertusallee | depart,turn straight,arrive |
|
||||
| waypoints | route | turns |
|
||||
| i,h | Kurfürstendamm,Rathenauplatz,Hubertusallee,Hubertusallee | depart,turn right,turn right,arrive |
|
||||
|
||||
# https://www.openstreetmap.org/#map=19/52.46339/13.40272
|
||||
Scenario: Do not merge links between segregated roads
|
||||
Given the node map
|
||||
"""
|
||||
f
|
||||
`````````` ..............
|
||||
` ` ` ` e - - - - - - - d
|
||||
a 1
|
||||
```````````.............. |
|
||||
`````````` b - - - - - - - c
|
||||
|
|
||||
|
|
||||
|
|
||||
|
|
||||
g
|
||||
"""
|
||||
|
||||
And the ways
|
||||
| nodes | name | oneway |
|
||||
| ab | germ | yes |
|
||||
| bc | ober | yes |
|
||||
| de | ober | yes |
|
||||
| ef | germ | yes |
|
||||
| eb | germ | no |
|
||||
| gb | germ | no |
|
||||
|
||||
When I route I should get
|
||||
| waypoints | route | turns |
|
||||
| a,c | germ,ober | depart,arrive |
|
||||
| a,g | germ,germ,germ | depart,continue right,arrive |
|
||||
| a,1 | germ,germ,germ | depart,continue left,arrive |
|
||||
| d,g | ober,germ,germ | depart,turn left,arrive |
|
||||
|
||||
# https://www.openstreetmap.org/#map=19/51.32888/6.57059
|
||||
Scenario: Places in presence of oneways
|
||||
Given the node map
|
||||
"""
|
||||
i l
|
||||
| |
|
||||
| |
|
||||
g - - - - - - - - - - - - - - - - - - - - - - - - - 1 - - - - - - - - - - - - - - - - - - - - - - - - - - - f
|
||||
| |
|
||||
| |
|
||||
a - - - b - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - 2 - - - - - - - - - - - - - - - c - - - d
|
||||
| |
|
||||
| |
|
||||
j k
|
||||
"""
|
||||
|
||||
And the ways
|
||||
| nodes | name | oneway |
|
||||
| ab | schwert | yes |
|
||||
| cd | schwert | yes |
|
||||
| ig | luise | yes |
|
||||
| bj | luise | yes |
|
||||
| kc | marianne | yes |
|
||||
| fl | marianne | yes |
|
||||
| bc | albrecht | no |
|
||||
| fg | albrecht | no |
|
||||
| gb | albrecht | yes |
|
||||
| cf | albrecht | yes |
|
||||
|
||||
When I route I should get
|
||||
| waypoints | route | turns |
|
||||
| a,l | schwert,albrecht,marianne,marianne | depart,new name straight,turn left,arrive |
|
||||
| a,j | schwert,luise,luise | depart,turn right,arrive |
|
||||
| a,1 | schwert,albrecht,albrecht,albrecht | depart,new name straight,continue uturn,arrive |
|
||||
| k,l | marianne,marianne | depart,arrive |
|
||||
| k,j | marianne,albrecht,luise,luise | depart,turn left,turn left,arrive |
|
||||
| k,d | marianne,schwert,schwert | depart,turn right,arrive |
|
||||
| i,j | luise,luise | depart,arrive |
|
||||
| i,d | luise,albrecht,schwert,schwert | depart,turn left,turn straight,arrive |
|
||||
| i,l | luise,albrecht,marianne,marianne | depart,turn left,turn left,arrive |
|
||||
|
||||
# https://www.openstreetmap.org/#map=19/52.46339/13.40272
|
||||
Scenario: Do not merge links between segregated roads
|
||||
Given the node map
|
||||
"""
|
||||
d
|
||||
f............... |
|
||||
`````````` .............. |
|
||||
a............... ` ` ` ` e
|
||||
``````````.............. 1
|
||||
`````````` b
|
||||
- - - - - - - c
|
||||
"""
|
||||
|
||||
And the ways
|
||||
| nodes | name | oneway |
|
||||
| ab | otto | yes |
|
||||
| bc | otto | no |
|
||||
| de | neu | no |
|
||||
| ef | otto | yes |
|
||||
| eb | otto | no |
|
||||
|
||||
When I route I should get
|
||||
| waypoints | route | turns | # |
|
||||
| a,c | otto,otto | depart,arrive | |
|
||||
| a,f | otto,otto,otto | depart,continue uturn,arrive | |
|
||||
| a,1 | otto,otto,otto | depart,continue left,arrive | |
|
||||
| a,d | otto,neu,neu | depart,turn left,arrive | |
|
||||
| c,1 | otto,otto | depart,arrive | |
|
||||
| c,f | otto,otto,otto | depart,continue left,arrive | Ideally, this would be depart,arrive, but the obvious discovery making the turn onto `1` from `c` obvious interferes here |
|
||||
|
||||
# https://www.openstreetmap.org/#map=18/50.94608/7.02030
|
||||
Scenario: Do not merge oneway places
|
||||
Given the node map
|
||||
"""
|
||||
j
|
||||
|
|
||||
|
|
||||
g - f - - - - - - - e
|
||||
| |
|
||||
| |
|
||||
| d
|
||||
| \
|
||||
| .c.
|
||||
a - - - - - - b` `
|
||||
| `
|
||||
| ` h
|
||||
|
|
||||
|
|
||||
i
|
||||
"""
|
||||
|
||||
And the ways
|
||||
| nodes | name | oneway |
|
||||
| efabc | kobe | yes |
|
||||
| edc | kobe | no |
|
||||
| fg | arn | no |
|
||||
| ia | kobu | yes |
|
||||
| hc | wei | no |
|
||||
| ej | wei | no |
|
||||
|
||||
When I route I should get
|
||||
| waypoints | route | turns |
|
||||
| j,h | wei,wei | depart,arrive |
|
||||
| a,d | kobe,kobe,kobe | depart,continue left,arrive |
|
||||
|
||||
@@ -126,3 +126,24 @@ Feature: Merging
|
||||
When I route I should get
|
||||
| waypoints | route | turns |
|
||||
| d,c | ,A100,A100 | depart,merge slight right,arrive |
|
||||
|
||||
|
||||
# https://www.openstreetmap.org/way/254299122
|
||||
@merge
|
||||
Scenario: Merge onto a motorway with junction references
|
||||
Given the node map
|
||||
"""
|
||||
a b c d
|
||||
e f
|
||||
"""
|
||||
|
||||
And the ways
|
||||
| nodes | name | junction:ref | highway | oneway |
|
||||
| abc | A100 | | motorway | yes |
|
||||
| cd | A100 | 1A | motorway | yes |
|
||||
| eb | | | motorway_link | yes |
|
||||
| cf | | 1B | motorway_link | yes |
|
||||
|
||||
When I route I should get
|
||||
| waypoints | route | turns |
|
||||
| e,d | ,A100,A100 | depart,merge slight left,arrive |
|
||||
|
||||
@@ -36,6 +36,36 @@ Feature: Simple Turns
|
||||
| f,a | depart,arrive | road,road | true:0,true:0 false:150 false:180;true:180 |
|
||||
| e,a | depart,turn slight right,arrive | turn,road,road | true:333;true:0 false:150 false:180;true:180 |
|
||||
|
||||
Scenario: Turning into splitting road - no improvement
|
||||
Given the node map
|
||||
"""
|
||||
a
|
||||
b
|
||||
/ |
|
||||
c d - e
|
||||
| |
|
||||
| |
|
||||
| |
|
||||
| |
|
||||
| |
|
||||
| |
|
||||
| |
|
||||
| |
|
||||
g f
|
||||
"""
|
||||
|
||||
And the ways
|
||||
| nodes | name | highway | oneway |
|
||||
| ab | road | primary | no |
|
||||
| bcg | road | primary | yes |
|
||||
| fdb | road | primary | yes |
|
||||
| ed | turn | primary | yes |
|
||||
|
||||
When I route I should get
|
||||
| waypoints | turns | route | intersections |
|
||||
| f,a | depart,arrive | road,road | true:0,true:0 false:90 false:180;true:180 |
|
||||
| e,a | depart,turn right,arrive | turn,road,road | true:270;true:0 false:90 false:180;true:180 |
|
||||
|
||||
Scenario: Turning into splitting road
|
||||
Given the node map
|
||||
"""
|
||||
|
||||
@@ -5,7 +5,7 @@ Feature: Basic Roundabout
|
||||
Given a grid size of 10 meters
|
||||
Given the profile file "car" initialized with
|
||||
"""
|
||||
profile.left_hand_driving = true
|
||||
profile.properties.left_hand_driving = true
|
||||
"""
|
||||
|
||||
Scenario: Roundabout exit counting for left sided driving
|
||||
|
||||
@@ -765,7 +765,7 @@ Feature: Basic Roundabout
|
||||
| e,h | 90 135 | edf,gch,gch,gch | depart,roundabout-exit-2,exit roundabout straight,arrive |
|
||||
| g,f | 45 90 | gch,edf,edf,edf | depart,roundabout-exit-2,exit roundabout right,arrive |
|
||||
| g,h | 45 135 | gch,gch,gch | depart,exit roundabout right,arrive |
|
||||
| e,e | 90 270 | edf,edf,edf,edf | depart,roundabout-exit-3,exit roundabout sharp left,arrive |
|
||||
| e,e | 90 270 | edf,edf,edf | depart,continue uturn,arrive |
|
||||
|
||||
Scenario: CCW and CW roundabouts with overlaps
|
||||
Given the node map
|
||||
|
||||
@@ -972,6 +972,8 @@ Feature: Simple Turns
|
||||
d
|
||||
|
||||
h
|
||||
|
||||
q
|
||||
"""
|
||||
|
||||
And the nodes
|
||||
@@ -981,16 +983,16 @@ Feature: Simple Turns
|
||||
And the ways
|
||||
| nodes | name | highway | oneway |
|
||||
| yf | yf | trunk_link | yes |
|
||||
| gfeh | Centreville Road | primary | |
|
||||
| gfehq | Centreville Road | primary | |
|
||||
| fi | fi | trunk_link | yes |
|
||||
| ij | Bloomingdale Road | residential | |
|
||||
| jkabx | Blue Star Memorial Hwy | trunk | |
|
||||
| jkabx | Blue Star Memorial Hwy | trunk | yes |
|
||||
| bcde | bcde | trunk_link | yes |
|
||||
| kh | kh | trunk_link | yes |
|
||||
|
||||
When I route I should get
|
||||
| waypoints | turns | route |
|
||||
| a,h | depart,off ramp right,turn sharp left,arrive | Blue Star Memorial Hwy,bcde,Centreville Road,Centreville Road |
|
||||
| a,q | depart,off ramp right,turn sharp left,arrive | Blue Star Memorial Hwy,bcde,Centreville Road,Centreville Road |
|
||||
|
||||
@todo
|
||||
# https://www.openstreetmap.org/#map=20/52.51609/13.41080
|
||||
|
||||
@@ -51,7 +51,7 @@ Feature: osrm-extract lua ways:get_nodes()
|
||||
| ab |
|
||||
And the data has been saved to disk
|
||||
|
||||
When I try to run "osrm-extract --profile {profile_file} {osm_file} --location-dependent-data test/data/regions/null-island.geojson --use-locations-cache=false"
|
||||
When I try to run "osrm-extract --profile {profile_file} {osm_file} --location-dependent-data test/data/regions/null-island.geojson --disable-location-cache"
|
||||
Then it should exit with an error
|
||||
And stderr should contain "invalid location"
|
||||
|
||||
@@ -79,7 +79,7 @@ Feature: osrm-extract lua ways:get_nodes()
|
||||
| ab |
|
||||
And the data has been saved to disk
|
||||
|
||||
When I run "osrm-extract --profile {profile_file} {osm_file} --location-dependent-data test/data/regions/null-island.geojson --use-locations-cache=false"
|
||||
When I run "osrm-extract --profile {profile_file} {osm_file} --location-dependent-data test/data/regions/null-island.geojson --disable-location-cache"
|
||||
Then it should exit successfully
|
||||
And stdout should contain "answer 42"
|
||||
And stdout should contain "boolean true"
|
||||
@@ -116,7 +116,7 @@ Feature: osrm-extract lua ways:get_nodes()
|
||||
| ef | Null Island |
|
||||
And the data has been saved to disk
|
||||
|
||||
When I run "osrm-extract --profile {profile_file} {osm_file} --location-dependent-data test/data/regions/null-island.geojson --location-dependent-data test/data/regions/hong-kong.geojson --use-locations-cache=false"
|
||||
When I run "osrm-extract --profile {profile_file} {osm_file} --location-dependent-data test/data/regions/null-island.geojson --location-dependent-data test/data/regions/hong-kong.geojson --disable-location-cache"
|
||||
Then it should exit successfully
|
||||
And stdout should not contain "1 GeoJSON polygon"
|
||||
And stdout should contain "2 GeoJSON polygons"
|
||||
|
||||
@@ -24,7 +24,7 @@ Feature: Invalid profile API versions
|
||||
Scenario: Profile API version too high
|
||||
Given the profile file
|
||||
"""
|
||||
api_version = 4
|
||||
api_version = 5
|
||||
"""
|
||||
And the node map
|
||||
"""
|
||||
|
||||
@@ -267,6 +267,10 @@ module.exports = function () {
|
||||
return this.extractInstructionList(instructions, s => s.mode);
|
||||
};
|
||||
|
||||
this.drivingSideList = (instructions) => {
|
||||
return this.extractInstructionList(instructions, s => s.driving_side);
|
||||
};
|
||||
|
||||
this.classesList = (instructions) => {
|
||||
return this.extractInstructionList(instructions, s => '[' + s.intersections.map(i => '(' + (i.classes ? i.classes.join(',') : '') + ')').join(',') + ']');
|
||||
};
|
||||
|
||||
@@ -35,7 +35,8 @@ module.exports = function () {
|
||||
if (err) return cb(err);
|
||||
if (body && body.length) {
|
||||
let destinations, exits, pronunciations, instructions, refs, bearings, turns, modes, times, classes,
|
||||
distances, summary, intersections, lanes, locations, annotation, weight_name, weights, approaches;
|
||||
distances, summary, intersections, lanes, locations, annotation, weight_name, weights, approaches,
|
||||
driving_sides;
|
||||
|
||||
let json = JSON.parse(body);
|
||||
|
||||
@@ -53,6 +54,7 @@ module.exports = function () {
|
||||
turns = this.turnList(json.routes[0]);
|
||||
intersections = this.intersectionList(json.routes[0]);
|
||||
modes = this.modeList(json.routes[0]);
|
||||
driving_sides = this.drivingSideList(json.routes[0]);
|
||||
classes = this.classesList(json.routes[0]);
|
||||
times = this.timeList(json.routes[0]);
|
||||
distances = this.distanceList(json.routes[0]);
|
||||
@@ -186,6 +188,10 @@ module.exports = function () {
|
||||
putValue('weight', weight);
|
||||
putValue('approach', approaches);
|
||||
|
||||
if (driving_sides) {
|
||||
putValue('driving_side', driving_sides);
|
||||
}
|
||||
|
||||
for (var key in row) {
|
||||
if (this.FuzzyMatch.match(got[key], row[key])) {
|
||||
got[key] = row[key];
|
||||
|
||||
@@ -31,40 +31,32 @@ Feature: Alternative route
|
||||
| 5 | 6 | dc,ca,ab,bd,dc,dc | |
|
||||
| 7 | 8 | ca,ab,bd,dc,ca,ca | |
|
||||
|
||||
# This test case does not work in a platform independent way
|
||||
# since it depends on a specific CH structure that is only
|
||||
# present on linux it seems.
|
||||
@4111 @todo
|
||||
Scenario: Alternative Loop Paths with single node path
|
||||
|
||||
@mld-only
|
||||
Scenario: Alternative loop paths on a single node with an asymmetric circle
|
||||
# The test checks only MLD implementation, alternatives results are unpredictable for CH on windows (#4691, #4693)
|
||||
Given a grid size of 10 meters
|
||||
Given the node map
|
||||
"""
|
||||
a1b2c3d
|
||||
|
||||
|
||||
e f
|
||||
a b c
|
||||
l d
|
||||
k e
|
||||
j f
|
||||
i h g
|
||||
"""
|
||||
|
||||
And the nodes
|
||||
| node | barrier |
|
||||
| i | bollard |
|
||||
| g | bollard |
|
||||
|
||||
And the ways
|
||||
| nodes | maxspeed |
|
||||
| ab | 30 |
|
||||
| bc | 3 |
|
||||
| cd | 30 |
|
||||
| ae | 30 |
|
||||
| ef | 30 |
|
||||
| fd | 30 |
|
||||
| nodes | oneway |
|
||||
| abcdefghijkla | no |
|
||||
|
||||
And the query options
|
||||
| alternatives | true |
|
||||
|
||||
When I route I should get
|
||||
| from | to | route | alternative |
|
||||
| b | c | bc,bc | ab,ae,ef,fd,cd,cd |
|
||||
#| c | b | bc,bc | cd,fd,ef,ae,ab,ab | # alternative path depends on phantom snapping order
|
||||
| 1 | c | ab,bc,bc | ab,ae,ef,fd,cd,cd |
|
||||
#| c | 1 | bc,ab | cd,fd,ef,ae,ab | # alternative path depends on phantom snapping order
|
||||
| 2 | c | bc,bc | |
|
||||
| c | 2 | bc,bc | |
|
||||
| 1 | 3 | ab,ae,ef,fd,cd | ab,bc,cd |
|
||||
#| 3 | 1 | cd,fd,ef,ae,ab | cd,bc,ab | # alternative path depends on phantom snapping order
|
||||
| b | 3 | bc,cd | ab,ae,ef,fd,cd |
|
||||
#| 3 | b | cd,bc,bc | cd,fd,ef,ae,ab,ab | # alternative path depends on phantom snapping order
|
||||
| from | to | route | alternative | weight |
|
||||
| e | k | abcdefghijkla,abcdefghijkla | abcdefghijkla,abcdefghijkla | 6.8 |
|
||||
|
||||
@@ -81,6 +81,8 @@ inline auto contractExcludableGraph(ContractorGraph contractor_graph_,
|
||||
auto filtered_core_graph =
|
||||
shared_core_graph.Filter([&filter](const NodeID node) { return filter[node]; });
|
||||
|
||||
contractGraph(filtered_core_graph, is_shared_core, is_shared_core, node_weights);
|
||||
|
||||
edge_container.Merge(toEdges<QueryEdge>(std::move(filtered_core_graph)));
|
||||
}
|
||||
|
||||
|
||||
@@ -33,22 +33,8 @@ namespace json
|
||||
namespace detail
|
||||
{
|
||||
|
||||
std::string instructionTypeToString(extractor::guidance::TurnType::Enum type);
|
||||
std::string instructionModifierToString(extractor::guidance::DirectionModifier::Enum modifier);
|
||||
|
||||
/**
|
||||
* Returns a string representing all instruction types (including internal types that
|
||||
* are normally not exposed in route responses)
|
||||
*
|
||||
* @param type the TurnType value to convert into a string
|
||||
* @return a string representing the turn type (e.g. `turn` or `continue`)
|
||||
*/
|
||||
std::string internalInstructionTypeToString(extractor::guidance::TurnType::Enum type);
|
||||
|
||||
util::json::Array coordinateToLonLat(const util::Coordinate coordinate);
|
||||
|
||||
std::string modeToString(const extractor::TravelMode mode);
|
||||
|
||||
/**
|
||||
* Ensures that a bearing value is a whole number, and clamped to the range 0-359
|
||||
*/
|
||||
|
||||
@@ -38,8 +38,50 @@ class NearestAPI final : public BaseAPI
|
||||
phantom_nodes.front().end(),
|
||||
waypoints.values.begin(),
|
||||
[this](const PhantomNodeWithDistance &phantom_with_distance) {
|
||||
auto waypoint = MakeWaypoint(phantom_with_distance.phantom_node);
|
||||
auto &phantom_node = phantom_with_distance.phantom_node;
|
||||
auto waypoint = MakeWaypoint(phantom_node);
|
||||
waypoint.values["distance"] = phantom_with_distance.distance;
|
||||
|
||||
util::json::Array nodes;
|
||||
|
||||
std::uint64_t from_node = 0;
|
||||
std::uint64_t to_node = 0;
|
||||
|
||||
std::vector<NodeID> forward_geometry;
|
||||
if (phantom_node.forward_segment_id.enabled)
|
||||
{
|
||||
auto segment_id = phantom_node.forward_segment_id.id;
|
||||
const auto geometry_id = facade.GetGeometryIndex(segment_id).id;
|
||||
forward_geometry =
|
||||
facade.GetUncompressedForwardGeometry(geometry_id);
|
||||
|
||||
auto osm_node_id = facade.GetOSMNodeIDOfNode(
|
||||
forward_geometry[phantom_node.fwd_segment_position]);
|
||||
to_node = static_cast<std::uint64_t>(osm_node_id);
|
||||
}
|
||||
|
||||
if (phantom_node.reverse_segment_id.enabled)
|
||||
{
|
||||
auto segment_id = phantom_node.reverse_segment_id.id;
|
||||
const auto geometry_id = facade.GetGeometryIndex(segment_id).id;
|
||||
std::vector<NodeID> geometry =
|
||||
facade.GetUncompressedForwardGeometry(geometry_id);
|
||||
auto osm_node_id = facade.GetOSMNodeIDOfNode(
|
||||
geometry[phantom_node.fwd_segment_position + 1]);
|
||||
from_node = static_cast<std::uint64_t>(osm_node_id);
|
||||
}
|
||||
else if (phantom_node.forward_segment_id.enabled &&
|
||||
phantom_node.fwd_segment_position > 0)
|
||||
{
|
||||
// In the case of one way, rely on forward segment only
|
||||
auto osm_node_id = facade.GetOSMNodeIDOfNode(
|
||||
forward_geometry[phantom_node.fwd_segment_position - 1]);
|
||||
from_node = static_cast<std::uint64_t>(osm_node_id);
|
||||
}
|
||||
nodes.values.push_back(from_node);
|
||||
nodes.values.push_back(to_node);
|
||||
waypoint.values["nodes"] = std::move(nodes);
|
||||
|
||||
return waypoint;
|
||||
});
|
||||
|
||||
|
||||
@@ -885,6 +885,11 @@ class ContiguousInternalMemoryDataFacadeBase : public BaseDataFacade
|
||||
// TODO: can be moved to a data block indexed by GeometryID
|
||||
return edge_based_node_data.IsLeftHandDriving(id);
|
||||
}
|
||||
|
||||
bool IsSegregated(const NodeID id) const override final
|
||||
{
|
||||
return edge_based_node_data.IsSegregated(id);
|
||||
}
|
||||
};
|
||||
|
||||
template <typename AlgorithmT> class ContiguousInternalMemoryDataFacade;
|
||||
|
||||
@@ -191,6 +191,8 @@ class BaseDataFacade
|
||||
virtual util::guidance::EntryClass GetEntryClass(const EdgeID turn_id) const = 0;
|
||||
|
||||
virtual bool IsLeftHandDriving(const NodeID id) const = 0;
|
||||
|
||||
virtual bool IsSegregated(const NodeID) const = 0;
|
||||
};
|
||||
}
|
||||
}
|
||||
|
||||
@@ -56,6 +56,7 @@ inline std::vector<RouteStep> assembleSteps(const datafacade::BaseDataFacade &fa
|
||||
const auto source_node_id = source_traversed_in_reverse ? source_node.reverse_segment_id.id
|
||||
: source_node.forward_segment_id.id;
|
||||
const auto source_name_id = facade.GetNameIndex(source_node_id);
|
||||
bool is_segregated = facade.IsSegregated(source_node_id);
|
||||
const auto source_mode = facade.GetTravelMode(source_node_id);
|
||||
auto source_classes = facade.GetClasses(facade.GetClassData(source_node_id));
|
||||
|
||||
@@ -127,6 +128,7 @@ inline std::vector<RouteStep> assembleSteps(const datafacade::BaseDataFacade &fa
|
||||
intersection.classes = facade.GetClasses(path_point.classes);
|
||||
|
||||
steps.push_back(RouteStep{step_name_id,
|
||||
is_segregated,
|
||||
name.to_string(),
|
||||
ref.to_string(),
|
||||
pronunciation.to_string(),
|
||||
@@ -141,15 +143,18 @@ inline std::vector<RouteStep> assembleSteps(const datafacade::BaseDataFacade &fa
|
||||
maneuver,
|
||||
leg_geometry.FrontIndex(segment_index),
|
||||
leg_geometry.BackIndex(segment_index) + 1,
|
||||
{intersection}});
|
||||
{intersection},
|
||||
path_point.is_left_hand_driving});
|
||||
|
||||
if (leg_data_index + 1 < leg_data.size())
|
||||
{
|
||||
step_name_id = leg_data[leg_data_index + 1].name_id;
|
||||
is_segregated = leg_data[leg_data_index + 1].is_segregated;
|
||||
}
|
||||
else
|
||||
{
|
||||
step_name_id = facade.GetNameIndex(target_node_id);
|
||||
is_segregated = facade.IsSegregated(target_node_id);
|
||||
}
|
||||
|
||||
// extract bearings
|
||||
@@ -205,6 +210,7 @@ inline std::vector<RouteStep> assembleSteps(const datafacade::BaseDataFacade &fa
|
||||
intersection.classes = facade.GetClasses(facade.GetClassData(target_node_id));
|
||||
BOOST_ASSERT(duration >= 0);
|
||||
steps.push_back(RouteStep{step_name_id,
|
||||
is_segregated,
|
||||
facade.GetNameForID(step_name_id).to_string(),
|
||||
facade.GetRefForID(step_name_id).to_string(),
|
||||
facade.GetPronunciationForID(step_name_id).to_string(),
|
||||
@@ -219,7 +225,8 @@ inline std::vector<RouteStep> assembleSteps(const datafacade::BaseDataFacade &fa
|
||||
maneuver,
|
||||
leg_geometry.FrontIndex(segment_index),
|
||||
leg_geometry.BackIndex(segment_index) + 1,
|
||||
{intersection}});
|
||||
{intersection},
|
||||
facade.IsLeftHandDriving(target_node_id)});
|
||||
}
|
||||
// In this case the source + target are on the same edge segment
|
||||
else
|
||||
@@ -247,6 +254,7 @@ inline std::vector<RouteStep> assembleSteps(const datafacade::BaseDataFacade &fa
|
||||
const EdgeWeight duration = std::max(0, target_duration - source_duration);
|
||||
|
||||
steps.push_back(RouteStep{source_name_id,
|
||||
is_segregated,
|
||||
facade.GetNameForID(source_name_id).to_string(),
|
||||
facade.GetRefForID(source_name_id).to_string(),
|
||||
facade.GetPronunciationForID(source_name_id).to_string(),
|
||||
@@ -261,7 +269,8 @@ inline std::vector<RouteStep> assembleSteps(const datafacade::BaseDataFacade &fa
|
||||
std::move(maneuver),
|
||||
leg_geometry.FrontIndex(segment_index),
|
||||
leg_geometry.BackIndex(segment_index) + 1,
|
||||
{intersection}});
|
||||
{intersection},
|
||||
facade.IsLeftHandDriving(source_node_id)});
|
||||
}
|
||||
|
||||
BOOST_ASSERT(segment_index == number_of_segments - 1);
|
||||
@@ -287,6 +296,7 @@ inline std::vector<RouteStep> assembleSteps(const datafacade::BaseDataFacade &fa
|
||||
|
||||
BOOST_ASSERT(!leg_geometry.locations.empty());
|
||||
steps.push_back(RouteStep{target_name_id,
|
||||
facade.IsSegregated(target_node_id),
|
||||
facade.GetNameForID(target_name_id).to_string(),
|
||||
facade.GetRefForID(target_name_id).to_string(),
|
||||
facade.GetPronunciationForID(target_name_id).to_string(),
|
||||
@@ -301,7 +311,8 @@ inline std::vector<RouteStep> assembleSteps(const datafacade::BaseDataFacade &fa
|
||||
std::move(maneuver),
|
||||
leg_geometry.locations.size() - 1,
|
||||
leg_geometry.locations.size(),
|
||||
{intersection}});
|
||||
{intersection},
|
||||
facade.IsLeftHandDriving(source_node_id)});
|
||||
|
||||
BOOST_ASSERT(steps.front().intersections.size() == 1);
|
||||
BOOST_ASSERT(steps.front().intersections.front().bearings.size() == 1);
|
||||
|
||||
@@ -121,9 +121,15 @@ inline bool haveSameMode(const RouteStep &first, const RouteStep &second, const
|
||||
// alias for readability
|
||||
inline bool haveSameName(const RouteStep &lhs, const RouteStep &rhs)
|
||||
{
|
||||
const auto has_name_or_ref = [](auto const &step) {
|
||||
return !step.name.empty() || !step.ref.empty();
|
||||
};
|
||||
|
||||
// make sure empty is not involved
|
||||
if (lhs.name_id == EMPTY_NAMEID || rhs.name_id == EMPTY_NAMEID)
|
||||
if (!has_name_or_ref(lhs) || !has_name_or_ref(rhs))
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
// easy check to not go over the strings if not necessary
|
||||
else if (lhs.name_id == rhs.name_id)
|
||||
|
||||
@@ -60,6 +60,7 @@ inline IntermediateIntersection getInvalidIntersection()
|
||||
struct RouteStep
|
||||
{
|
||||
unsigned name_id;
|
||||
bool is_segregated;
|
||||
std::string name;
|
||||
std::string ref;
|
||||
std::string pronunciation;
|
||||
@@ -76,6 +77,7 @@ struct RouteStep
|
||||
std::size_t geometry_begin;
|
||||
std::size_t geometry_end;
|
||||
std::vector<IntermediateIntersection> intersections;
|
||||
bool is_left_hand_driving;
|
||||
|
||||
// remove all information from the route step, marking it as invalid (used to indicate empty
|
||||
// steps to be removed).
|
||||
@@ -123,12 +125,13 @@ inline void RouteStep::Invalidate()
|
||||
duration = 0;
|
||||
distance = 0;
|
||||
weight = 0;
|
||||
mode = TRAVEL_MODE_INACCESSIBLE;
|
||||
mode = extractor::TRAVEL_MODE_INACCESSIBLE;
|
||||
maneuver = getInvalidStepManeuver();
|
||||
geometry_begin = 0;
|
||||
geometry_end = 0;
|
||||
intersections.clear();
|
||||
intersections.push_back(getInvalidIntersection());
|
||||
is_left_hand_driving = false;
|
||||
}
|
||||
|
||||
// Elongate by another step in front
|
||||
|
||||
@@ -27,6 +27,8 @@ struct PathData
|
||||
NodeID turn_via_node;
|
||||
// name of the street that leads to the turn
|
||||
unsigned name_id;
|
||||
// segregated edge-based node that leads to the turn
|
||||
bool is_segregated;
|
||||
// weight that is traveled on the segment until the turn is reached
|
||||
// including the turn weight, if one exists
|
||||
EdgeWeight weight_until_turn;
|
||||
@@ -57,6 +59,9 @@ struct PathData
|
||||
util::guidance::TurnBearing pre_turn_bearing;
|
||||
// bearing (as seen from the intersection) post-turn
|
||||
util::guidance::TurnBearing post_turn_bearing;
|
||||
|
||||
// Driving side of the turn
|
||||
bool is_left_hand_driving;
|
||||
};
|
||||
|
||||
struct InternalRouteResult
|
||||
|
||||
@@ -164,6 +164,7 @@ void annotatePath(const FacadeT &facade,
|
||||
const auto turn_id = edge_data.turn_id; // edge-based graph edge index
|
||||
const auto node_id = *node_from; // edge-based graph node index
|
||||
const auto name_index = facade.GetNameIndex(node_id);
|
||||
const bool is_segregated = facade.IsSegregated(node_id);
|
||||
const auto turn_instruction = facade.GetTurnInstructionForEdgeID(turn_id);
|
||||
const extractor::TravelMode travel_mode = facade.GetTravelMode(node_id);
|
||||
const auto classes = facade.GetClassData(node_id);
|
||||
@@ -185,12 +186,15 @@ void annotatePath(const FacadeT &facade,
|
||||
: 0);
|
||||
const std::size_t end_index = weight_vector.size();
|
||||
|
||||
bool is_left_hand_driving = facade.IsLeftHandDriving(node_id);
|
||||
|
||||
BOOST_ASSERT(start_index >= 0);
|
||||
BOOST_ASSERT(start_index < end_index);
|
||||
for (std::size_t segment_idx = start_index; segment_idx < end_index; ++segment_idx)
|
||||
{
|
||||
unpacked_path.push_back(PathData{id_vector[segment_idx + 1],
|
||||
name_index,
|
||||
is_segregated,
|
||||
weight_vector[segment_idx],
|
||||
0,
|
||||
duration_vector[segment_idx],
|
||||
@@ -202,7 +206,8 @@ void annotatePath(const FacadeT &facade,
|
||||
EMPTY_ENTRY_CLASS,
|
||||
datasource_vector[segment_idx],
|
||||
util::guidance::TurnBearing(0),
|
||||
util::guidance::TurnBearing(0)});
|
||||
util::guidance::TurnBearing(0),
|
||||
is_left_hand_driving});
|
||||
}
|
||||
BOOST_ASSERT(unpacked_path.size() > 0);
|
||||
if (facade.HasLaneData(turn_id))
|
||||
@@ -254,6 +259,7 @@ void annotatePath(const FacadeT &facade,
|
||||
// t: fwd_segment 3
|
||||
// -> (U, v), (v, w), (w, x)
|
||||
// note that (x, t) is _not_ included but needs to be added later.
|
||||
bool is_target_left_hand_driving = facade.IsLeftHandDriving(target_node_id);
|
||||
for (std::size_t segment_idx = start_index; segment_idx != end_index;
|
||||
(start_index < end_index ? ++segment_idx : --segment_idx))
|
||||
{
|
||||
@@ -262,6 +268,7 @@ void annotatePath(const FacadeT &facade,
|
||||
unpacked_path.push_back(
|
||||
PathData{id_vector[start_index < end_index ? segment_idx + 1 : segment_idx - 1],
|
||||
facade.GetNameIndex(target_node_id),
|
||||
facade.IsSegregated(target_node_id),
|
||||
weight_vector[segment_idx],
|
||||
0,
|
||||
duration_vector[segment_idx],
|
||||
@@ -273,7 +280,8 @@ void annotatePath(const FacadeT &facade,
|
||||
EMPTY_ENTRY_CLASS,
|
||||
datasource_vector[segment_idx],
|
||||
util::guidance::TurnBearing(0),
|
||||
util::guidance::TurnBearing(0)});
|
||||
util::guidance::TurnBearing(0),
|
||||
is_target_left_hand_driving});
|
||||
}
|
||||
|
||||
if (unpacked_path.size() > 0)
|
||||
|
||||
@@ -75,6 +75,7 @@ class EdgeBasedGraphFactory
|
||||
const std::unordered_set<NodeID> &traffic_lights,
|
||||
const std::vector<util::Coordinate> &coordinates,
|
||||
const util::NameTable &name_table,
|
||||
const std::unordered_set<EdgeID> &segregated_edges,
|
||||
guidance::LaneDescriptionMap &lane_description_map);
|
||||
|
||||
void Run(ScriptingEnvironment &scripting_environment,
|
||||
@@ -157,6 +158,7 @@ class EdgeBasedGraphFactory
|
||||
const CompressedEdgeContainer &m_compressed_edge_container;
|
||||
|
||||
const util::NameTable &name_table;
|
||||
const std::unordered_set<EdgeID> &segregated_edges;
|
||||
guidance::LaneDescriptionMap &lane_description_map;
|
||||
|
||||
// In the edge based graph, any traversable (non reversed) edge of the node-based graph forms a
|
||||
|
||||
@@ -12,7 +12,8 @@ struct EdgeBasedNode
|
||||
{
|
||||
GeometryID geometry_id;
|
||||
ComponentID component_id;
|
||||
AnnotationID annotation_id;
|
||||
std::uint32_t annotation_id : 31;
|
||||
std::uint32_t segregated : 1;
|
||||
};
|
||||
|
||||
} // namespace extractor
|
||||
|
||||
@@ -14,41 +14,33 @@ namespace extractor
|
||||
|
||||
struct ExtractionTurn
|
||||
{
|
||||
ExtractionTurn(const guidance::ConnectedRoad &turn,
|
||||
ExtractionTurn(double angle,
|
||||
int number_of_roads,
|
||||
bool is_u_turn,
|
||||
bool has_traffic_light,
|
||||
bool source_restricted,
|
||||
bool target_restricted,
|
||||
bool is_left_hand_driving)
|
||||
: angle(180. - turn.angle), turn_type(turn.instruction.type),
|
||||
direction_modifier(turn.instruction.direction_modifier),
|
||||
bool is_left_hand_driving,
|
||||
TravelMode source_mode,
|
||||
TravelMode target_mode)
|
||||
: angle(180. - angle), number_of_roads(number_of_roads), is_u_turn(is_u_turn),
|
||||
has_traffic_light(has_traffic_light), source_restricted(source_restricted),
|
||||
target_restricted(target_restricted), is_left_hand_driving(is_left_hand_driving),
|
||||
weight(0.), duration(0.)
|
||||
{
|
||||
}
|
||||
|
||||
ExtractionTurn(bool has_traffic_light,
|
||||
bool source_restricted,
|
||||
bool target_restricted,
|
||||
bool is_left_hand_driving)
|
||||
: angle(0), turn_type(guidance::TurnType::NoTurn),
|
||||
direction_modifier(guidance::DirectionModifier::Straight),
|
||||
has_traffic_light(has_traffic_light), source_restricted(source_restricted),
|
||||
target_restricted(target_restricted), is_left_hand_driving(is_left_hand_driving),
|
||||
weight(0.), duration(0.)
|
||||
weight(0.), duration(0.), source_mode(source_mode), target_mode(target_mode)
|
||||
{
|
||||
}
|
||||
|
||||
const double angle;
|
||||
const guidance::TurnType::Enum turn_type;
|
||||
const guidance::DirectionModifier::Enum direction_modifier;
|
||||
const int number_of_roads;
|
||||
const bool is_u_turn;
|
||||
const bool has_traffic_light;
|
||||
const bool source_restricted;
|
||||
const bool target_restricted;
|
||||
const bool is_left_hand_driving;
|
||||
|
||||
double weight;
|
||||
double duration;
|
||||
TravelMode source_mode;
|
||||
TravelMode target_mode;
|
||||
};
|
||||
}
|
||||
}
|
||||
|
||||
@@ -47,15 +47,16 @@ struct ExtractionWay
|
||||
duration = -1;
|
||||
weight = -1;
|
||||
name.clear();
|
||||
ref.clear();
|
||||
forward_ref.clear();
|
||||
backward_ref.clear();
|
||||
pronunciation.clear();
|
||||
destinations.clear();
|
||||
exits.clear();
|
||||
turn_lanes_forward.clear();
|
||||
turn_lanes_backward.clear();
|
||||
road_classification = guidance::RoadClassification();
|
||||
forward_travel_mode = TRAVEL_MODE_INACCESSIBLE;
|
||||
backward_travel_mode = TRAVEL_MODE_INACCESSIBLE;
|
||||
forward_travel_mode = extractor::TRAVEL_MODE_INACCESSIBLE;
|
||||
backward_travel_mode = extractor::TRAVEL_MODE_INACCESSIBLE;
|
||||
roundabout = false;
|
||||
circular = false;
|
||||
is_startpoint = true;
|
||||
@@ -67,8 +68,10 @@ struct ExtractionWay
|
||||
// wrappers to allow assigning nil (nullptr) to string values
|
||||
void SetName(const char *value) { detail::maybeSetString(name, value); }
|
||||
const char *GetName() const { return name.c_str(); }
|
||||
void SetRef(const char *value) { detail::maybeSetString(ref, value); }
|
||||
const char *GetRef() const { return ref.c_str(); }
|
||||
void SetForwardRef(const char *value) { detail::maybeSetString(forward_ref, value); }
|
||||
const char *GetForwardRef() const { return forward_ref.c_str(); }
|
||||
void SetBackwardRef(const char *value) { detail::maybeSetString(backward_ref, value); }
|
||||
const char *GetBackwardRef() const { return backward_ref.c_str(); }
|
||||
void SetDestinations(const char *value) { detail::maybeSetString(destinations, value); }
|
||||
const char *GetDestinations() const { return destinations.c_str(); }
|
||||
void SetExits(const char *value) { detail::maybeSetString(exits, value); }
|
||||
@@ -101,15 +104,16 @@ struct ExtractionWay
|
||||
// weight of the whole way in both directions
|
||||
double weight;
|
||||
std::string name;
|
||||
std::string ref;
|
||||
std::string forward_ref;
|
||||
std::string backward_ref;
|
||||
std::string pronunciation;
|
||||
std::string destinations;
|
||||
std::string exits;
|
||||
std::string turn_lanes_forward;
|
||||
std::string turn_lanes_backward;
|
||||
guidance::RoadClassification road_classification;
|
||||
TravelMode forward_travel_mode : 4;
|
||||
TravelMode backward_travel_mode : 4;
|
||||
extractor::TravelMode forward_travel_mode : 4;
|
||||
extractor::TravelMode backward_travel_mode : 4;
|
||||
|
||||
// Boolean flags
|
||||
bool roundabout : 1;
|
||||
|
||||
@@ -47,6 +47,7 @@ namespace extractor
|
||||
|
||||
class ScriptingEnvironment;
|
||||
struct ProfileProperties;
|
||||
class NodeBasedGraphFactory;
|
||||
|
||||
class Extractor
|
||||
{
|
||||
@@ -71,6 +72,7 @@ class Extractor
|
||||
const std::unordered_set<NodeID> &traffic_lights,
|
||||
const std::vector<TurnRestriction> &turn_restrictions,
|
||||
const std::vector<ConditionalTurnRestriction> &conditional_turn_restrictions,
|
||||
const std::unordered_set<EdgeID> &segregated_edges,
|
||||
// might have to be updated to add new lane combinations
|
||||
guidance::LaneDescriptionMap &turn_lane_map,
|
||||
// for calculating turn penalties
|
||||
@@ -100,6 +102,13 @@ class Extractor
|
||||
void WriteConditionalRestrictions(
|
||||
const std::string &path,
|
||||
std::vector<ConditionalTurnRestriction> &conditional_turn_restrictions);
|
||||
|
||||
// Find all "segregated" edges, e.g. edges that can be skipped in turn instructions.
|
||||
// The main cases are:
|
||||
// - middle edges between two osm ways in one logic road (U-turn)
|
||||
// - staggered intersections (X-cross)
|
||||
// - square/circle intersections
|
||||
std::unordered_set<EdgeID> FindSegregatedNodes(NodeBasedGraphFactory &factory);
|
||||
};
|
||||
}
|
||||
}
|
||||
|
||||
@@ -63,7 +63,8 @@ class ExtractorCallbacks
|
||||
// actually maps to name ids
|
||||
using MapKey = std::tuple<std::string, std::string, std::string, std::string, std::string>;
|
||||
using MapVal = unsigned;
|
||||
std::unordered_map<MapKey, MapVal> string_map;
|
||||
using StringMap = std::unordered_map<MapKey, MapVal>;
|
||||
StringMap string_map;
|
||||
ExtractionContainers &external_memory;
|
||||
std::unordered_map<std::string, ClassData> &classes_map;
|
||||
guidance::LaneDescriptionMap &lane_description_map;
|
||||
|
||||
@@ -69,6 +69,7 @@ struct ExtractorConfig final : storage::IOConfig
|
||||
".osrm.cnbg",
|
||||
".osrm.cnbg_to_ebg"}),
|
||||
requested_num_threads(0),
|
||||
parse_conditionals(false),
|
||||
use_locations_cache(true)
|
||||
{
|
||||
}
|
||||
|
||||
@@ -26,7 +26,7 @@ const double constexpr DISTINCTION_RATIO = 2;
|
||||
const double constexpr MAX_ROUNDABOUT_RADIUS = 15;
|
||||
// Unnamed small roundabouts that look like intersections are announced as turns,
|
||||
// guard against data issues or such roundabout intersections getting too large.
|
||||
const double constexpr MAX_ROUNDABOUT_INTERSECTION_RADIUS = 25;
|
||||
const double constexpr MAX_ROUNDABOUT_INTERSECTION_RADIUS = 15;
|
||||
|
||||
const double constexpr INCREASES_BY_FOURTY_PERCENT = 1.4;
|
||||
|
||||
|
||||
@@ -140,6 +140,22 @@ class MergableRoadDetector
|
||||
// The detector wants to prevent merges that are connected to `b-e`
|
||||
bool IsLinkRoad(const NodeID intersection_node, const MergableRoadData &road) const;
|
||||
|
||||
// The condition suppresses roads merging for intersections like
|
||||
// . .
|
||||
// . .
|
||||
// ---- ----
|
||||
// . .
|
||||
// . .
|
||||
// but will allow roads merging for intersections like
|
||||
// -------
|
||||
// / \
|
||||
// ---- ----
|
||||
// \ /
|
||||
// -------
|
||||
bool IsCircularShape(const NodeID intersection_node,
|
||||
const MergableRoadData &lhs,
|
||||
const MergableRoadData &rhs) const;
|
||||
|
||||
const util::NodeBasedDynamicGraph &node_based_graph;
|
||||
const EdgeBasedNodeDataContainer &node_data_container;
|
||||
const std::vector<util::Coordinate> &node_coordinates;
|
||||
@@ -149,6 +165,9 @@ class MergableRoadDetector
|
||||
// name detection
|
||||
const util::NameTable &name_table;
|
||||
const SuffixTable &street_name_suffix_table;
|
||||
|
||||
// limit for detecting circles / parallel roads
|
||||
const static double constexpr distance_to_extract = 150;
|
||||
};
|
||||
|
||||
} // namespace guidance
|
||||
|
||||
@@ -123,7 +123,8 @@ struct SelectStraightmostRoadByNameAndOnlyChoice
|
||||
{
|
||||
SelectStraightmostRoadByNameAndOnlyChoice(const NameID desired_name_id,
|
||||
const double initial_bearing,
|
||||
const bool requires_entry);
|
||||
const bool requires_entry,
|
||||
const bool stop_on_ambiguous_turns);
|
||||
|
||||
/*
|
||||
* !! REQUIRED - Function for the use of TraverseRoad in the graph walker.
|
||||
@@ -141,6 +142,7 @@ struct SelectStraightmostRoadByNameAndOnlyChoice
|
||||
const NameID desired_name_id;
|
||||
const double initial_bearing;
|
||||
const bool requires_entry;
|
||||
const bool stop_on_ambiguous_turns;
|
||||
};
|
||||
|
||||
// find the next intersection given a hop limit
|
||||
|
||||
@@ -0,0 +1,108 @@
|
||||
#ifndef OSRM_EXTRACTOR_GUIDANCE_STATISTICS_HANDLER_HPP_
|
||||
#define OSRM_EXTRACTOR_GUIDANCE_STATISTICS_HANDLER_HPP_
|
||||
|
||||
#include "extractor/guidance/intersection.hpp"
|
||||
#include "extractor/guidance/intersection_handler.hpp"
|
||||
#include "extractor/guidance/turn_instruction.hpp"
|
||||
|
||||
#include "util/log.hpp"
|
||||
|
||||
#include <algorithm>
|
||||
#include <iomanip>
|
||||
#include <iterator>
|
||||
#include <mutex>
|
||||
#include <unordered_map>
|
||||
|
||||
#include <cstdint>
|
||||
|
||||
namespace osrm
|
||||
{
|
||||
namespace extractor
|
||||
{
|
||||
namespace guidance
|
||||
{
|
||||
|
||||
// Unconditionally runs over all intersections and gathers statistics for
|
||||
// instruction turn types and direction modifiers (see turn_instruction.hpp).
|
||||
class StatisticsHandler final : public IntersectionHandler
|
||||
{
|
||||
public:
|
||||
StatisticsHandler(const IntersectionGenerator &intersection_generator,
|
||||
const util::NodeBasedDynamicGraph &node_based_graph,
|
||||
const EdgeBasedNodeDataContainer &node_data_container,
|
||||
const std::vector<util::Coordinate> &coordinates,
|
||||
const util::NameTable &name_table,
|
||||
const SuffixTable &street_name_suffix_table)
|
||||
: IntersectionHandler(node_based_graph,
|
||||
node_data_container,
|
||||
coordinates,
|
||||
name_table,
|
||||
street_name_suffix_table,
|
||||
intersection_generator)
|
||||
{
|
||||
}
|
||||
|
||||
~StatisticsHandler() override final
|
||||
{
|
||||
const auto add_second = [](const auto acc, const auto &kv) { return acc + kv.second; };
|
||||
|
||||
const auto num_types =
|
||||
std::accumulate(begin(type_hist), end(type_hist), std::uint64_t{0}, add_second);
|
||||
const auto num_modifiers =
|
||||
std::accumulate(begin(modifier_hist), end(modifier_hist), std::uint64_t{0}, add_second);
|
||||
|
||||
util::Log() << "Assigned " << num_types << " turn instruction types:";
|
||||
|
||||
for (const auto &kv : type_hist)
|
||||
if (kv.second > 0)
|
||||
util::Log() << std::fixed << std::setprecision(2)
|
||||
<< internalInstructionTypeToString(kv.first) << ": " << kv.second
|
||||
<< " (" << (kv.second / static_cast<float>(num_types) * 100.) << "%)";
|
||||
|
||||
util::Log() << "Assigned " << num_modifiers << " turn instruction modifiers:";
|
||||
|
||||
for (const auto &kv : modifier_hist)
|
||||
if (kv.second > 0)
|
||||
util::Log() << std::fixed << std::setprecision(2)
|
||||
<< instructionModifierToString(kv.first) << ": " << kv.second << " ("
|
||||
<< (kv.second / static_cast<float>(num_modifiers) * 100.) << "%)";
|
||||
}
|
||||
|
||||
bool canProcess(const NodeID, const EdgeID, const Intersection &) const override final
|
||||
{
|
||||
return true;
|
||||
}
|
||||
|
||||
Intersection
|
||||
operator()(const NodeID, const EdgeID, Intersection intersection) const override final
|
||||
{
|
||||
// Lock histograms updates on a per-intersection basis.
|
||||
std::lock_guard<std::mutex> defer{lock};
|
||||
|
||||
// Generate histograms for all roads; this way we will get duplicates
|
||||
// which we would not get doing it after EBF generation. But we want
|
||||
// numbers closer to the handlers and see how often handlers ran.
|
||||
for (const auto &road : intersection)
|
||||
{
|
||||
|
||||
const auto type = road.instruction.type;
|
||||
const auto modifier = road.instruction.direction_modifier;
|
||||
|
||||
type_hist[type] += 1;
|
||||
modifier_hist[modifier] += 1;
|
||||
}
|
||||
|
||||
return intersection;
|
||||
}
|
||||
|
||||
private:
|
||||
mutable std::mutex lock;
|
||||
mutable std::unordered_map<TurnType::Enum, std::uint64_t> type_hist;
|
||||
mutable std::unordered_map<DirectionModifier::Enum, std::uint64_t> modifier_hist;
|
||||
};
|
||||
|
||||
} // namespace guidance
|
||||
} // namespace extractor
|
||||
} // namespace osrm
|
||||
|
||||
#endif // OSRM_EXTRACTOR_GUIDANCE_VALIDATION_HANDLER_HPP_
|
||||
@@ -10,6 +10,7 @@
|
||||
#include "extractor/guidance/motorway_handler.hpp"
|
||||
#include "extractor/guidance/roundabout_handler.hpp"
|
||||
#include "extractor/guidance/sliproad_handler.hpp"
|
||||
#include "extractor/guidance/statistics_handler.hpp"
|
||||
#include "extractor/guidance/suppress_mode_handler.hpp"
|
||||
#include "extractor/guidance/turn_classification.hpp"
|
||||
#include "extractor/guidance/turn_handler.hpp"
|
||||
@@ -89,6 +90,7 @@ class TurnAnalysis
|
||||
const SliproadHandler sliproad_handler;
|
||||
const SuppressModeHandler suppress_mode_handler;
|
||||
const DrivewayHandler driveway_handler;
|
||||
const StatisticsHandler statistics_handler;
|
||||
|
||||
// Utility function, setting basic turn types. Prepares for normal turn handling.
|
||||
Intersection
|
||||
|
||||
@@ -309,6 +309,86 @@ inline DirectionModifier::Enum bearingToDirectionModifier(const double bearing)
|
||||
return extractor::guidance::DirectionModifier::Left;
|
||||
}
|
||||
|
||||
namespace detail
|
||||
{
|
||||
|
||||
const constexpr char *modifier_names[] = {"uturn",
|
||||
"sharp right",
|
||||
"right",
|
||||
"slight right",
|
||||
"straight",
|
||||
"slight left",
|
||||
"left",
|
||||
"sharp left"};
|
||||
|
||||
/**
|
||||
* Human readable values for TurnType enum values
|
||||
*/
|
||||
struct TurnTypeName
|
||||
{
|
||||
// String value we return with our API
|
||||
const char *external_name;
|
||||
// Internal only string name for the turn type - useful for debugging
|
||||
// and used by debug tiles for visualizing hidden turn types
|
||||
const char *internal_name;
|
||||
};
|
||||
|
||||
// Indexes in this list correspond to the Enum values of osrm::extractor::guidance::TurnType
|
||||
const constexpr TurnTypeName turn_type_names[] = {
|
||||
{"invalid", "(not set)"},
|
||||
{"new name", "new name"},
|
||||
{"continue", "continue"},
|
||||
{"turn", "turn"},
|
||||
{"merge", "merge"},
|
||||
{"on ramp", "on ramp"},
|
||||
{"off ramp", "off ramp"},
|
||||
{"fork", "fork"},
|
||||
{"end of road", "end of road"},
|
||||
{"notification", "notification"},
|
||||
{"roundabout", "enter roundabout"},
|
||||
{"exit roundabout", "enter and exit roundabout"},
|
||||
{"rotary", "enter rotary"},
|
||||
{"exit rotary", "enter and exit rotary"},
|
||||
{"roundabout turn", "enter roundabout turn"},
|
||||
{"roundabout turn", "enter and exit roundabout turn"},
|
||||
{"use lane", "use lane"},
|
||||
{"invalid", "(noturn)"},
|
||||
{"invalid", "(suppressed)"},
|
||||
{"roundabout", "roundabout"},
|
||||
{"exit roundabout", "exit roundabout"},
|
||||
{"rotary", "rotary"},
|
||||
{"exit rotary", "exit rotary"},
|
||||
{"roundabout turn", "roundabout turn"},
|
||||
{"exit roundabout", "exit roundabout turn"},
|
||||
{"invalid", "(stay on roundabout)"},
|
||||
{"invalid", "(sliproad)"}};
|
||||
|
||||
} // ns detail
|
||||
|
||||
inline std::string instructionTypeToString(const TurnType::Enum type)
|
||||
{
|
||||
static_assert(sizeof(detail::turn_type_names) / sizeof(detail::turn_type_names[0]) >=
|
||||
TurnType::MaxTurnType,
|
||||
"Some turn types have no string representation.");
|
||||
return detail::turn_type_names[static_cast<std::size_t>(type)].external_name;
|
||||
}
|
||||
|
||||
inline std::string internalInstructionTypeToString(const TurnType::Enum type)
|
||||
{
|
||||
static_assert(sizeof(detail::turn_type_names) / sizeof(detail::turn_type_names[0]) >=
|
||||
TurnType::MaxTurnType,
|
||||
"Some turn types have no string representation.");
|
||||
return detail::turn_type_names[static_cast<std::size_t>(type)].internal_name;
|
||||
}
|
||||
|
||||
inline std::string instructionModifierToString(const DirectionModifier::Enum modifier)
|
||||
{
|
||||
static_assert(sizeof(detail::modifier_names) / sizeof(detail::modifier_names[0]) >=
|
||||
DirectionModifier::MaxDirectionModifier,
|
||||
"Some direction modifiers have no string representation.");
|
||||
return detail::modifier_names[static_cast<std::size_t>(modifier)];
|
||||
}
|
||||
|
||||
} // namespace guidance
|
||||
} // namespace extractor
|
||||
} // namespace osrm
|
||||
|
||||
@@ -71,6 +71,16 @@ struct NodeBasedEdgeAnnotation
|
||||
std::tie(name_id, classes, travel_mode, is_left_hand_driving) ==
|
||||
std::tie(other.name_id, other.classes, other.travel_mode, other.is_left_hand_driving));
|
||||
}
|
||||
|
||||
bool operator<(const NodeBasedEdgeAnnotation &other) const
|
||||
{
|
||||
return (std::tie(name_id, lane_description_id, classes, travel_mode, is_left_hand_driving) <
|
||||
std::tie(other.name_id,
|
||||
other.lane_description_id,
|
||||
other.classes,
|
||||
other.travel_mode,
|
||||
other.is_left_hand_driving));
|
||||
}
|
||||
};
|
||||
|
||||
struct NodeBasedEdge
|
||||
|
||||
@@ -41,7 +41,7 @@ class NodeBasedGraphFactory
|
||||
std::vector<TurnRestriction> &turn_restrictions,
|
||||
std::vector<ConditionalTurnRestriction> &conditional_turn_restrictions);
|
||||
|
||||
auto const &GetGraph() const { return compressed_output_graph; }
|
||||
auto const &GetGraph() { return compressed_output_graph; }
|
||||
auto const &GetBarriers() const { return barriers; }
|
||||
auto const &GetTrafficSignals() const { return traffic_signals; }
|
||||
auto &GetCompressedEdges() { return compressed_edge_container; }
|
||||
@@ -75,7 +75,7 @@ class NodeBasedGraphFactory
|
||||
// unreferenced entries
|
||||
void CompressAnnotationData();
|
||||
|
||||
// After produce, this will contain a compresse version of the node-based graph
|
||||
// After produce, this will contain a compressed version of the node-based graph
|
||||
util::NodeBasedDynamicGraph compressed_output_graph;
|
||||
// To store the meta-data for the graph that is purely annotative / not used for the navigation
|
||||
// itself. Since the edges of a node-based graph form the nodes of the edge based graphs, we
|
||||
|
||||
@@ -77,6 +77,8 @@ template <storage::Ownership Ownership> class EdgeBasedNodeDataContainerImpl
|
||||
return annotation_data[nodes[node_id].annotation_id].is_left_hand_driving;
|
||||
}
|
||||
|
||||
bool IsSegregated(const NodeID node_id) const { return nodes[node_id].segregated; }
|
||||
|
||||
NameID GetNameID(const NodeID node_id) const
|
||||
{
|
||||
return annotation_data[nodes[node_id].annotation_id].name_id;
|
||||
@@ -105,13 +107,8 @@ template <storage::Ownership Ownership> class EdgeBasedNodeDataContainerImpl
|
||||
// between a large set of nodes
|
||||
AnnotationID NumberOfAnnotations() const { return annotation_data.size(); }
|
||||
|
||||
EdgeBasedNode &GetNode(const NodeID node_id) { return nodes[node_id]; }
|
||||
EdgeBasedNode const &GetNode(const NodeID node_id) const { return nodes[node_id]; }
|
||||
|
||||
NodeBasedEdgeAnnotation &GetAnnotation(const AnnotationID annotation)
|
||||
{
|
||||
return annotation_data[annotation];
|
||||
}
|
||||
NodeBasedEdgeAnnotation const &GetAnnotation(const AnnotationID annotation) const
|
||||
{
|
||||
return annotation_data[annotation];
|
||||
|
||||
@@ -21,7 +21,7 @@ struct OriginalEdgeData
|
||||
LaneDataID lane_data_id,
|
||||
guidance::TurnInstruction turn_instruction,
|
||||
EntryClassID entry_classid,
|
||||
TravelMode travel_mode,
|
||||
extractor::TravelMode travel_mode,
|
||||
util::guidance::TurnBearing pre_turn_bearing,
|
||||
util::guidance::TurnBearing post_turn_bearing)
|
||||
: via_geometry(via_geometry), name_id(name_id), entry_classid(entry_classid),
|
||||
@@ -34,7 +34,8 @@ struct OriginalEdgeData
|
||||
: via_geometry{std::numeric_limits<unsigned>::max() >> 1, false},
|
||||
name_id(std::numeric_limits<unsigned>::max()), entry_classid(INVALID_ENTRY_CLASSID),
|
||||
lane_data_id(INVALID_LANE_DATAID), turn_instruction(guidance::TurnInstruction::INVALID()),
|
||||
travel_mode(TRAVEL_MODE_INACCESSIBLE), pre_turn_bearing(0.0), post_turn_bearing(0.0)
|
||||
travel_mode(extractor::TRAVEL_MODE_INACCESSIBLE), pre_turn_bearing(0.0),
|
||||
post_turn_bearing(0.0)
|
||||
{
|
||||
}
|
||||
|
||||
@@ -43,7 +44,7 @@ struct OriginalEdgeData
|
||||
EntryClassID entry_classid;
|
||||
LaneDataID lane_data_id;
|
||||
guidance::TurnInstruction turn_instruction;
|
||||
TravelMode travel_mode;
|
||||
extractor::TravelMode travel_mode;
|
||||
util::guidance::TurnBearing pre_turn_bearing;
|
||||
util::guidance::TurnBearing post_turn_bearing;
|
||||
};
|
||||
|
||||
@@ -68,7 +68,7 @@ class Sol2ScriptingEnvironment final : public ScriptingEnvironment
|
||||
{
|
||||
public:
|
||||
static const constexpr int SUPPORTED_MIN_API_VERSION = 0;
|
||||
static const constexpr int SUPPORTED_MAX_API_VERSION = 3;
|
||||
static const constexpr int SUPPORTED_MAX_API_VERSION = 4;
|
||||
|
||||
explicit Sol2ScriptingEnvironment(
|
||||
const std::string &file_name,
|
||||
|
||||
@@ -29,6 +29,7 @@ SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
#define TRAVEL_MODE_HPP
|
||||
|
||||
#include <cstdint>
|
||||
#include <string>
|
||||
|
||||
namespace osrm
|
||||
{
|
||||
@@ -38,8 +39,6 @@ namespace extractor
|
||||
// This is a char instead of a typed enum, so that we can
|
||||
// pack it into e.g. a "TravelMode mode : 4" packed bitfield
|
||||
using TravelMode = std::uint8_t;
|
||||
}
|
||||
}
|
||||
|
||||
const constexpr osrm::extractor::TravelMode TRAVEL_MODE_INACCESSIBLE = 0;
|
||||
const constexpr osrm::extractor::TravelMode TRAVEL_MODE_DRIVING = 1;
|
||||
@@ -55,4 +54,56 @@ const constexpr osrm::extractor::TravelMode TRAVEL_MODE_RIVER_UP = 10;
|
||||
const constexpr osrm::extractor::TravelMode TRAVEL_MODE_RIVER_DOWN = 11;
|
||||
const constexpr osrm::extractor::TravelMode TRAVEL_MODE_ROUTE = 12;
|
||||
|
||||
// FIXME this actually needs to be configurable from the profiles
|
||||
inline std::string travelModeToString(const TravelMode mode)
|
||||
{
|
||||
std::string token;
|
||||
switch (mode)
|
||||
{
|
||||
case TRAVEL_MODE_INACCESSIBLE:
|
||||
token = "inaccessible";
|
||||
break;
|
||||
case TRAVEL_MODE_DRIVING:
|
||||
token = "driving";
|
||||
break;
|
||||
case TRAVEL_MODE_CYCLING:
|
||||
token = "cycling";
|
||||
break;
|
||||
case TRAVEL_MODE_WALKING:
|
||||
token = "walking";
|
||||
break;
|
||||
case TRAVEL_MODE_FERRY:
|
||||
token = "ferry";
|
||||
break;
|
||||
case TRAVEL_MODE_TRAIN:
|
||||
token = "train";
|
||||
break;
|
||||
case TRAVEL_MODE_PUSHING_BIKE:
|
||||
token = "pushing bike";
|
||||
break;
|
||||
case TRAVEL_MODE_STEPS_UP:
|
||||
token = "steps up";
|
||||
break;
|
||||
case TRAVEL_MODE_STEPS_DOWN:
|
||||
token = "steps down";
|
||||
break;
|
||||
case TRAVEL_MODE_RIVER_UP:
|
||||
token = "river upstream";
|
||||
break;
|
||||
case TRAVEL_MODE_RIVER_DOWN:
|
||||
token = "river downstream";
|
||||
break;
|
||||
case TRAVEL_MODE_ROUTE:
|
||||
token = "route";
|
||||
break;
|
||||
default:
|
||||
token = "other";
|
||||
break;
|
||||
}
|
||||
return token;
|
||||
}
|
||||
|
||||
} // ns extractor
|
||||
} // ns osrm
|
||||
|
||||
#endif /* TRAVEL_MODE_HPP */
|
||||
|
||||
@@ -44,22 +44,20 @@ namespace updater
|
||||
struct UpdaterConfig final : storage::IOConfig
|
||||
{
|
||||
UpdaterConfig()
|
||||
: IOConfig(
|
||||
{
|
||||
".osrm.ebg",
|
||||
".osrm.turn_weight_penalties",
|
||||
".osrm.turn_duration_penalties",
|
||||
".osrm.turn_penalties_index",
|
||||
".osrm.nbg_nodes",
|
||||
".osrm.ebg_nodes",
|
||||
".osrm.edges",
|
||||
".osrm.geometry",
|
||||
".osrm.fileIndex",
|
||||
".osrm.properties",
|
||||
".osrm.restrictions",
|
||||
},
|
||||
{},
|
||||
{".osrm.datasource_names"})
|
||||
: IOConfig({".osrm.ebg",
|
||||
".osrm.turn_weight_penalties",
|
||||
".osrm.turn_duration_penalties",
|
||||
".osrm.turn_penalties_index",
|
||||
".osrm.nbg_nodes",
|
||||
".osrm.ebg_nodes",
|
||||
".osrm.edges",
|
||||
".osrm.geometry",
|
||||
".osrm.fileIndex",
|
||||
".osrm.properties",
|
||||
".osrm.restrictions"},
|
||||
{},
|
||||
{".osrm.datasource_names"}),
|
||||
valid_now(0)
|
||||
{
|
||||
}
|
||||
|
||||
|
||||
@@ -22,6 +22,7 @@ namespace util
|
||||
|
||||
namespace guidance
|
||||
{
|
||||
|
||||
inline void print(const engine::guidance::RouteStep &step)
|
||||
{
|
||||
std::cout << static_cast<int>(step.maneuver.instruction.type) << " "
|
||||
|
||||
@@ -2,6 +2,7 @@
|
||||
#define OSRM_GEOJSON_DEBUG_LOGGER_HPP
|
||||
|
||||
#include <fstream>
|
||||
#include <iomanip>
|
||||
#include <mutex>
|
||||
#include <string>
|
||||
|
||||
@@ -105,6 +106,8 @@ class GeojsonLogger
|
||||
std::lock_guard<std::mutex> guard(lock);
|
||||
ofs.open(logfile, std::ios::binary);
|
||||
|
||||
ofs << std::setprecision(12);
|
||||
|
||||
// set up a feature collection
|
||||
ofs << "{\n\t\"type\": \"FeatureCollection\",\n\t\"features\": [\n\t";
|
||||
// remember whether we need to output a colon
|
||||
|
||||
+1
-1
@@ -1,6 +1,6 @@
|
||||
{
|
||||
"name": "osrm",
|
||||
"version": "5.13.0-rc.1",
|
||||
"version": "5.14.0-rc.1",
|
||||
"private": false,
|
||||
"description": "The Open Source Routing Machine is a high performance routing engine written in C++14 designed to run on OpenStreetMap data.",
|
||||
"dependencies": {
|
||||
|
||||
@@ -48,6 +48,7 @@ function setup()
|
||||
'toll_booth',
|
||||
'sally_port',
|
||||
'gate',
|
||||
'lift_gate',
|
||||
'no',
|
||||
'block'
|
||||
},
|
||||
|
||||
+7
-31
@@ -1,6 +1,6 @@
|
||||
-- Car profile
|
||||
|
||||
api_version = 3
|
||||
api_version = 4
|
||||
|
||||
Set = require('lib/set')
|
||||
Sequence = require('lib/sequence')
|
||||
@@ -35,6 +35,7 @@ function setup()
|
||||
turn_penalty = 7.5,
|
||||
speed_reduction = 0.8,
|
||||
turn_bias = 1.075,
|
||||
cardinal_directions = false,
|
||||
|
||||
-- a list of suffixes to suppress in name change instructions. The suffixes also include common substrings of each other
|
||||
suffix_list = {
|
||||
@@ -161,6 +162,7 @@ function setup()
|
||||
'tertiary_link',
|
||||
'residential',
|
||||
'living_street',
|
||||
'unclassified'
|
||||
},
|
||||
|
||||
construction_whitelist = Set {
|
||||
@@ -402,34 +404,8 @@ function process_way(profile, way, result, relations)
|
||||
|
||||
WayHandlers.run(profile, way, result, data, handlers, relations)
|
||||
|
||||
local parsed_rel_list = {}
|
||||
local rel_id_list = relations:get_relations(way)
|
||||
for i, rel_id in ipairs(rel_id_list) do
|
||||
local rel = relations:relation(rel_id)
|
||||
parsed_rel_list[i] = Relations.parse_route_relation(rel, way, relations)
|
||||
end
|
||||
|
||||
-- now process relations data
|
||||
local matched_refs = nil;
|
||||
if result.ref then
|
||||
local match_res = Relations.match_to_ref(parsed_rel_list, result.ref)
|
||||
|
||||
local ref = ''
|
||||
for _, m in pairs(match_res) do
|
||||
if ref ~= '' then
|
||||
ref = ref .. '; '
|
||||
end
|
||||
|
||||
if m.dir then
|
||||
ref = ref .. m.ref .. ' $' .. m.dir
|
||||
else
|
||||
ref = ref .. m.ref
|
||||
end
|
||||
end
|
||||
|
||||
-- print(result.name, ref)
|
||||
|
||||
result.ref = ref
|
||||
if profile.cardinal_directions then
|
||||
Relations.process_way_refs(way, relations, result)
|
||||
end
|
||||
end
|
||||
|
||||
@@ -444,14 +420,14 @@ function process_turn(profile, turn)
|
||||
turn.duration = profile.properties.traffic_light_penalty
|
||||
end
|
||||
|
||||
if turn.turn_type ~= turn_type.no_turn then
|
||||
if turn.number_of_roads > 2 or turn.source_mode ~= turn.target_mode or turn.is_u_turn then
|
||||
if turn.angle >= 0 then
|
||||
turn.duration = turn.duration + turn_penalty / (1 + math.exp( -((13 / turn_bias) * turn.angle/180 - 6.5*turn_bias)))
|
||||
else
|
||||
turn.duration = turn.duration + turn_penalty / (1 + math.exp( -((13 * turn_bias) * -turn.angle/180 - 6.5/turn_bias)))
|
||||
end
|
||||
|
||||
if turn.direction_modifier == direction_modifier.u_turn then
|
||||
if turn.is_u_turn then
|
||||
turn.duration = turn.duration + profile.properties.u_turn_penalty
|
||||
end
|
||||
end
|
||||
|
||||
@@ -33,6 +33,7 @@ function setup()
|
||||
'toll_booth',
|
||||
'sally_port',
|
||||
'gate',
|
||||
'lift_gate',
|
||||
'no',
|
||||
'kerb',
|
||||
'block'
|
||||
|
||||
@@ -41,7 +41,7 @@ function Relations.match_to_ref(relations, ref)
|
||||
local result_match = {}
|
||||
local order = {}
|
||||
for i, r in ipairs(references) do
|
||||
result_match[r] = false
|
||||
result_match[r] = { forward = nil, backward = nil }
|
||||
order[i] = r
|
||||
end
|
||||
|
||||
@@ -65,7 +65,7 @@ function Relations.match_to_ref(relations, ref)
|
||||
if direction then
|
||||
local best_score = -1
|
||||
local best_ref = nil
|
||||
|
||||
|
||||
function find_best(scores)
|
||||
if scores then
|
||||
for k ,v in pairs(scores) do
|
||||
@@ -79,9 +79,21 @@ function Relations.match_to_ref(relations, ref)
|
||||
|
||||
find_best(name_scores)
|
||||
find_best(ref_scores)
|
||||
|
||||
|
||||
if best_ref then
|
||||
result_match[best_ref] = direction
|
||||
local result_direction = result_match[best_ref]
|
||||
|
||||
local is_forward = rel["route_forward"]
|
||||
if is_forward == nil then
|
||||
result_direction.forward = direction
|
||||
result_direction.backward = direction
|
||||
elseif is_forward == true then
|
||||
result_direction.forward = direction
|
||||
else
|
||||
result_direction.backward = direction
|
||||
end
|
||||
|
||||
result_match[best_ref] = result_direction
|
||||
end
|
||||
end
|
||||
|
||||
@@ -182,7 +194,6 @@ function Relations.parse_route_relation(rel, way, relations)
|
||||
local super_dir = get_direction_from_superrel(rel, relations)
|
||||
|
||||
-- check if there are data error
|
||||
|
||||
if (result_direction ~= nil) and (super_dir ~= nil) and (result_direction ~= super_dir) then
|
||||
print('ERROR: conflicting relation directions found for way ' .. way:id() ..
|
||||
' relation direction is ' .. result_direction .. ' superrelation direction is ' .. super_dir)
|
||||
@@ -192,11 +203,59 @@ function Relations.parse_route_relation(rel, way, relations)
|
||||
end
|
||||
|
||||
result['route_direction'] = result_direction
|
||||
|
||||
if role == 'forward' then
|
||||
result['route_forward'] = true
|
||||
elseif role == 'backward' then
|
||||
result['route_forward'] = false
|
||||
else
|
||||
result['route_forward'] = nil
|
||||
end
|
||||
|
||||
add_extra_data(m)
|
||||
end
|
||||
|
||||
|
||||
return result
|
||||
end
|
||||
|
||||
return Relations
|
||||
function Relations.process_way_refs(way, relations, result)
|
||||
local parsed_rel_list = {}
|
||||
local rel_id_list = relations:get_relations(way)
|
||||
for i, rel_id in ipairs(rel_id_list) do
|
||||
local rel = relations:relation(rel_id)
|
||||
parsed_rel_list[i] = Relations.parse_route_relation(rel, way, relations)
|
||||
end
|
||||
|
||||
-- now process relations data
|
||||
local matched_refs = nil;
|
||||
if result.ref then
|
||||
local match_res = Relations.match_to_ref(parsed_rel_list, result.ref)
|
||||
|
||||
function gen_ref(is_forward)
|
||||
local ref = ''
|
||||
for _, m in pairs(match_res) do
|
||||
if ref ~= '' then
|
||||
ref = ref .. '; '
|
||||
end
|
||||
|
||||
local dir = m.dir.forward
|
||||
if is_forward == false then
|
||||
dir = m.dir.backward
|
||||
end
|
||||
|
||||
if dir then
|
||||
ref = ref .. m.ref .. ' $' .. dir
|
||||
else
|
||||
ref = ref .. m.ref
|
||||
end
|
||||
end
|
||||
|
||||
return ref
|
||||
end
|
||||
|
||||
result.forward_ref = gen_ref(true)
|
||||
result.backward_ref = gen_ref(false)
|
||||
end
|
||||
end
|
||||
|
||||
return Relations
|
||||
|
||||
@@ -563,7 +563,7 @@ function WayHandlers.driving_side(profile, way, result, data)
|
||||
elseif driving_side == 'right' then
|
||||
result.is_left_hand_driving = false
|
||||
else
|
||||
result.is_left_hand_driving = profile.left_hand_driving
|
||||
result.is_left_hand_driving = profile.properties.left_hand_driving
|
||||
end
|
||||
end
|
||||
|
||||
|
||||
@@ -1,5 +1,7 @@
|
||||
#include "engine/api/json_factory.hpp"
|
||||
#include "extractor/guidance/turn_instruction.hpp"
|
||||
#include "extractor/travel_mode.hpp"
|
||||
|
||||
#include "engine/api/json_factory.hpp"
|
||||
#include "engine/hint.hpp"
|
||||
#include "engine/polyline_compressor.hpp"
|
||||
#include "util/integer_range.hpp"
|
||||
@@ -32,59 +34,6 @@ namespace json
|
||||
namespace detail
|
||||
{
|
||||
|
||||
const constexpr char *modifier_names[] = {"uturn",
|
||||
"sharp right",
|
||||
"right",
|
||||
"slight right",
|
||||
"straight",
|
||||
"slight left",
|
||||
"left",
|
||||
"sharp left"};
|
||||
|
||||
/**
|
||||
* Human readable values for TurnType enum values
|
||||
*/
|
||||
struct TurnTypeName
|
||||
{
|
||||
// String value we return with our API
|
||||
const char *external_name;
|
||||
// Internal only string name for the turn type - useful for debugging
|
||||
// and used by debug tiles for visualizing hidden turn types
|
||||
const char *internal_name;
|
||||
};
|
||||
|
||||
// Indexes in this list correspond to the Enum values of osrm::extractor::guidance::TurnType
|
||||
const constexpr TurnTypeName turn_type_names[] = {
|
||||
{"invalid", "(not set)"},
|
||||
{"new name", "new name"},
|
||||
{"continue", "continue"},
|
||||
{"turn", "turn"},
|
||||
{"merge", "merge"},
|
||||
{"on ramp", "on ramp"},
|
||||
{"off ramp", "off ramp"},
|
||||
{"fork", "fork"},
|
||||
{"end of road", "end of road"},
|
||||
{"notification", "notification"},
|
||||
{"roundabout", "enter roundabout"},
|
||||
{"exit roundabout", "enter and exit roundabout"},
|
||||
{"rotary", "enter rotary"},
|
||||
{"exit rotary", "enter and exit rotary"},
|
||||
{"roundabout turn", "enter roundabout turn"},
|
||||
{"roundabout turn", "enter and exit roundabout turn"},
|
||||
{"use lane", "use lane"},
|
||||
{"invalid", "(noturn)"},
|
||||
{"invalid", "(suppressed)"},
|
||||
{"roundabout", "roundabout"},
|
||||
{"exit roundabout", "exit roundabout"},
|
||||
{"rotary", "rotary"},
|
||||
{"exit rotary", "exit rotary"},
|
||||
{"roundabout turn", "roundabout turn"},
|
||||
{"exit roundabout", "exit roundabout turn"},
|
||||
{"invalid", "(stay on roundabout)"},
|
||||
{"invalid", "(sliproad)"}};
|
||||
|
||||
const constexpr char *waypoint_type_names[] = {"invalid", "arrive", "depart"};
|
||||
|
||||
// Check whether to include a modifier in the result of the API
|
||||
inline bool isValidModifier(const guidance::StepManeuver maneuver)
|
||||
{
|
||||
@@ -97,20 +46,6 @@ inline bool hasValidLanes(const guidance::IntermediateIntersection &intersection
|
||||
return intersection.lanes.lanes_in_turn > 0;
|
||||
}
|
||||
|
||||
std::string instructionTypeToString(const TurnType::Enum type)
|
||||
{
|
||||
static_assert(sizeof(turn_type_names) / sizeof(turn_type_names[0]) >= TurnType::MaxTurnType,
|
||||
"Some turn types have no string representation.");
|
||||
return turn_type_names[static_cast<std::size_t>(type)].external_name;
|
||||
}
|
||||
|
||||
std::string internalInstructionTypeToString(const TurnType::Enum type)
|
||||
{
|
||||
static_assert(sizeof(turn_type_names) / sizeof(turn_type_names[0]) >= TurnType::MaxTurnType,
|
||||
"Some turn types have no string representation.");
|
||||
return turn_type_names[static_cast<std::size_t>(type)].internal_name;
|
||||
}
|
||||
|
||||
util::json::Array lanesFromIntersection(const guidance::IntermediateIntersection &intersection)
|
||||
{
|
||||
BOOST_ASSERT(intersection.lanes.lanes_in_turn >= 1);
|
||||
@@ -135,13 +70,7 @@ util::json::Array lanesFromIntersection(const guidance::IntermediateIntersection
|
||||
return result;
|
||||
}
|
||||
|
||||
std::string instructionModifierToString(const DirectionModifier::Enum modifier)
|
||||
{
|
||||
static_assert(sizeof(modifier_names) / sizeof(modifier_names[0]) >=
|
||||
DirectionModifier::MaxDirectionModifier,
|
||||
"Some direction modifiers has not string representation.");
|
||||
return modifier_names[static_cast<std::size_t>(modifier)];
|
||||
}
|
||||
const constexpr char *waypoint_type_names[] = {"invalid", "arrive", "depart"};
|
||||
|
||||
std::string waypointTypeToString(const guidance::WaypointType waypoint_type)
|
||||
{
|
||||
@@ -159,55 +88,6 @@ util::json::Array coordinateToLonLat(const util::Coordinate coordinate)
|
||||
return array;
|
||||
}
|
||||
|
||||
// FIXME this actually needs to be configurable from the profiles
|
||||
std::string modeToString(const extractor::TravelMode mode)
|
||||
{
|
||||
std::string token;
|
||||
switch (mode)
|
||||
{
|
||||
case TRAVEL_MODE_INACCESSIBLE:
|
||||
token = "inaccessible";
|
||||
break;
|
||||
case TRAVEL_MODE_DRIVING:
|
||||
token = "driving";
|
||||
break;
|
||||
case TRAVEL_MODE_CYCLING:
|
||||
token = "cycling";
|
||||
break;
|
||||
case TRAVEL_MODE_WALKING:
|
||||
token = "walking";
|
||||
break;
|
||||
case TRAVEL_MODE_FERRY:
|
||||
token = "ferry";
|
||||
break;
|
||||
case TRAVEL_MODE_TRAIN:
|
||||
token = "train";
|
||||
break;
|
||||
case TRAVEL_MODE_PUSHING_BIKE:
|
||||
token = "pushing bike";
|
||||
break;
|
||||
case TRAVEL_MODE_STEPS_UP:
|
||||
token = "steps up";
|
||||
break;
|
||||
case TRAVEL_MODE_STEPS_DOWN:
|
||||
token = "steps down";
|
||||
break;
|
||||
case TRAVEL_MODE_RIVER_UP:
|
||||
token = "river upstream";
|
||||
break;
|
||||
case TRAVEL_MODE_RIVER_DOWN:
|
||||
token = "river downstream";
|
||||
break;
|
||||
case TRAVEL_MODE_ROUTE:
|
||||
token = "route";
|
||||
break;
|
||||
default:
|
||||
token = "other";
|
||||
break;
|
||||
}
|
||||
return token;
|
||||
}
|
||||
|
||||
} // namespace detail
|
||||
|
||||
util::json::Object makeStepManeuver(const guidance::StepManeuver &maneuver)
|
||||
@@ -217,7 +97,7 @@ util::json::Object makeStepManeuver(const guidance::StepManeuver &maneuver)
|
||||
std::string maneuver_type;
|
||||
|
||||
if (maneuver.waypoint_type == guidance::WaypointType::None)
|
||||
maneuver_type = detail::instructionTypeToString(maneuver.instruction.type);
|
||||
maneuver_type = extractor::guidance::instructionTypeToString(maneuver.instruction.type);
|
||||
else
|
||||
maneuver_type = detail::waypointTypeToString(maneuver.waypoint_type);
|
||||
|
||||
@@ -227,8 +107,8 @@ util::json::Object makeStepManeuver(const guidance::StepManeuver &maneuver)
|
||||
step_maneuver.values["type"] = std::move(maneuver_type);
|
||||
|
||||
if (detail::isValidModifier(maneuver))
|
||||
step_maneuver.values["modifier"] =
|
||||
detail::instructionModifierToString(maneuver.instruction.direction_modifier);
|
||||
step_maneuver.values["modifier"] = extractor::guidance::instructionModifierToString(
|
||||
maneuver.instruction.direction_modifier);
|
||||
|
||||
step_maneuver.values["location"] = detail::coordinateToLonLat(maneuver.location);
|
||||
step_maneuver.values["bearing_before"] = detail::roundAndClampBearing(maneuver.bearing_before);
|
||||
@@ -312,9 +192,10 @@ util::json::Object makeRouteStep(guidance::RouteStep step, util::json::Value geo
|
||||
}
|
||||
}
|
||||
|
||||
route_step.values["mode"] = detail::modeToString(std::move(step.mode));
|
||||
route_step.values["mode"] = extractor::travelModeToString(std::move(step.mode));
|
||||
route_step.values["maneuver"] = makeStepManeuver(std::move(step.maneuver));
|
||||
route_step.values["geometry"] = std::move(geometry);
|
||||
route_step.values["driving_side"] = step.is_left_hand_driving ? "left" : "right";
|
||||
|
||||
util::json::Array intersections;
|
||||
intersections.values.reserve(step.intersections.size());
|
||||
|
||||
@@ -51,15 +51,15 @@ double findTotalTurnAngle(const RouteStep &entry_step, const RouteStep &exit_ste
|
||||
util::bearing::angleBetween(entry_step_entry_bearing, exit_step_exit_bearing);
|
||||
|
||||
// both angles are in the same direction, the total turn gets increased
|
||||
//
|
||||
//
|
||||
// a ---- b
|
||||
// \
|
||||
// \
|
||||
// c
|
||||
// |
|
||||
// d
|
||||
//
|
||||
// Will be considered just like
|
||||
//
|
||||
//
|
||||
// a -----b
|
||||
// |
|
||||
// c
|
||||
@@ -89,11 +89,11 @@ double findTotalTurnAngle(const RouteStep &entry_step, const RouteStep &exit_ste
|
||||
else
|
||||
{
|
||||
// to prevent ignoring angles like
|
||||
//
|
||||
//
|
||||
// a -- b
|
||||
// |
|
||||
// c -- d
|
||||
//
|
||||
//
|
||||
// We don't combine both turn angles here but keep the very first turn angle.
|
||||
// We choose the first one, since we consider the first maneuver in a merge range the
|
||||
// important one
|
||||
@@ -186,8 +186,9 @@ void AdjustToCombinedTurnStrategy::operator()(RouteStep &step_at_turn_location,
|
||||
{
|
||||
const auto angle = findTotalTurnAngle(step_at_turn_location, transfer_from_step);
|
||||
|
||||
// Forks point to left/right. By doing a combined angle, we would risk ending up with
|
||||
// unreasonable fork instrucitons. The direction of a fork only depends on the forking location,
|
||||
// Forks and merges point to left/right. By doing a combined angle, we would risk ending up with
|
||||
// unreasonable fork instrucitons. The direction of a fork or a merge only depends on the
|
||||
// location,
|
||||
// not further angles coming up
|
||||
//
|
||||
// d
|
||||
@@ -195,7 +196,8 @@ void AdjustToCombinedTurnStrategy::operator()(RouteStep &step_at_turn_location,
|
||||
// a - b
|
||||
//
|
||||
// could end up as `fork left` for `a-b-c`, instead of fork-right
|
||||
const auto new_modifier = hasTurnType(step_at_turn_location, TurnType::Fork)
|
||||
const auto new_modifier = hasTurnType(step_at_turn_location, TurnType::Fork) ||
|
||||
hasTurnType(step_at_turn_location, TurnType::Merge)
|
||||
? step_at_turn_location.maneuver.instruction.direction_modifier
|
||||
: getTurnDirection(angle);
|
||||
|
||||
@@ -439,13 +441,14 @@ RouteSteps collapseTurnInstructions(RouteSteps steps)
|
||||
TransferSignageStrategy(),
|
||||
NoModificationStrategy());
|
||||
}
|
||||
|
||||
// if the current collapsing triggers, we can check for advanced scenarios that only are
|
||||
// possible after an inital collapse step (e.g. name change right after a u-turn)
|
||||
//
|
||||
//
|
||||
// f - e - d
|
||||
// | |
|
||||
// a - b - c
|
||||
//
|
||||
//
|
||||
// In this scenario, bc and de might belong to a different road than a-b and f-e (since
|
||||
// there are no fix conventions how to label them in segregated intersections). These steps
|
||||
// might only become apparent after some initial collapsing
|
||||
|
||||
+152
-30
@@ -1,5 +1,7 @@
|
||||
#include "engine/plugins/tile.hpp"
|
||||
#include "extractor/guidance/turn_instruction.hpp"
|
||||
|
||||
#include "engine/plugins/plugin_base.hpp"
|
||||
#include "engine/plugins/tile.hpp"
|
||||
|
||||
#include "util/coordinate_calculation.hpp"
|
||||
#include "util/string_view.hpp"
|
||||
@@ -67,7 +69,7 @@ template <typename T> struct ValueIndexer
|
||||
return offset;
|
||||
}
|
||||
|
||||
std::size_t indexOf(const T &value) { return value_offsets[value]; };
|
||||
std::size_t indexOf(const T &value) { return value_offsets[value]; }
|
||||
|
||||
const std::vector<T> &values() { return used_values; }
|
||||
|
||||
@@ -182,25 +184,8 @@ inline void encodePoint(const FixedPoint &pt, protozero::packed_field_uint32 &ge
|
||||
geometry.add_element(protozero::encode_zigzag32(dy));
|
||||
}
|
||||
|
||||
/**
|
||||
* Returnx the x1,y1,x2,y2 pixel coordinates of a line in a given
|
||||
* tile.
|
||||
*
|
||||
* @param start the first coordinate of the line
|
||||
* @param target the last coordinate of the line
|
||||
* @param tile_bbox the boundaries of the tile, in mercator coordinates
|
||||
* @return a FixedLine with coordinates relative to the tile_bbox.
|
||||
*/
|
||||
FixedLine coordinatesToTileLine(const util::Coordinate start,
|
||||
const util::Coordinate target,
|
||||
const BBox &tile_bbox)
|
||||
linestring_t floatLineToTileLine(const FloatLine &geo_line, const BBox &tile_bbox)
|
||||
{
|
||||
FloatLine geo_line;
|
||||
geo_line.emplace_back(static_cast<double>(util::toFloating(start.lon)),
|
||||
static_cast<double>(util::toFloating(start.lat)));
|
||||
geo_line.emplace_back(static_cast<double>(util::toFloating(target.lon)),
|
||||
static_cast<double>(util::toFloating(target.lat)));
|
||||
|
||||
linestring_t unclipped_line;
|
||||
|
||||
for (auto const &pt : geo_line)
|
||||
@@ -219,8 +204,65 @@ FixedLine coordinatesToTileLine(const util::Coordinate start,
|
||||
boost::geometry::append(unclipped_line, point_t(px, py));
|
||||
}
|
||||
|
||||
multi_linestring_t clipped_line;
|
||||
return unclipped_line;
|
||||
}
|
||||
|
||||
std::vector<FixedLine> coordinatesToTileLine(const std::vector<util::Coordinate> &points,
|
||||
const BBox &tile_bbox)
|
||||
{
|
||||
FloatLine geo_line;
|
||||
for (auto const &c : points)
|
||||
{
|
||||
geo_line.emplace_back(static_cast<double>(util::toFloating(c.lon)),
|
||||
static_cast<double>(util::toFloating(c.lat)));
|
||||
}
|
||||
|
||||
linestring_t unclipped_line = floatLineToTileLine(geo_line, tile_bbox);
|
||||
|
||||
multi_linestring_t clipped_line;
|
||||
boost::geometry::intersection(clip_box, unclipped_line, clipped_line);
|
||||
|
||||
std::vector<FixedLine> result;
|
||||
|
||||
// b::g::intersection might return a line with one point if the
|
||||
// original line was very short and coords were dupes
|
||||
for (auto const &cl : clipped_line)
|
||||
{
|
||||
if (cl.size() < 2)
|
||||
continue;
|
||||
|
||||
FixedLine tile_line;
|
||||
for (const auto &p : cl)
|
||||
tile_line.emplace_back(p.get<0>(), p.get<1>());
|
||||
|
||||
result.emplace_back(std::move(tile_line));
|
||||
}
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
/**
|
||||
* Return the x1,y1,x2,y2 pixel coordinates of a line in a given
|
||||
* tile.
|
||||
*
|
||||
* @param start the first coordinate of the line
|
||||
* @param target the last coordinate of the line
|
||||
* @param tile_bbox the boundaries of the tile, in mercator coordinates
|
||||
* @return a FixedLine with coordinates relative to the tile_bbox.
|
||||
*/
|
||||
FixedLine coordinatesToTileLine(const util::Coordinate start,
|
||||
const util::Coordinate target,
|
||||
const BBox &tile_bbox)
|
||||
{
|
||||
FloatLine geo_line;
|
||||
geo_line.emplace_back(static_cast<double>(util::toFloating(start.lon)),
|
||||
static_cast<double>(util::toFloating(start.lat)));
|
||||
geo_line.emplace_back(static_cast<double>(util::toFloating(target.lon)),
|
||||
static_cast<double>(util::toFloating(target.lat)));
|
||||
|
||||
linestring_t unclipped_line = floatLineToTileLine(geo_line, tile_bbox);
|
||||
|
||||
multi_linestring_t clipped_line;
|
||||
boost::geometry::intersection(clip_box, unclipped_line, clipped_line);
|
||||
|
||||
FixedLine tile_line;
|
||||
@@ -229,12 +271,9 @@ FixedLine coordinatesToTileLine(const util::Coordinate start,
|
||||
// original line was very short and coords were dupes
|
||||
if (!clipped_line.empty() && clipped_line[0].size() == 2)
|
||||
{
|
||||
if (clipped_line[0].size() == 2)
|
||||
for (const auto &p : clipped_line[0])
|
||||
{
|
||||
for (const auto &p : clipped_line[0])
|
||||
{
|
||||
tile_line.emplace_back(p.get<0>(), p.get<1>());
|
||||
}
|
||||
tile_line.emplace_back(p.get<0>(), p.get<1>());
|
||||
}
|
||||
}
|
||||
|
||||
@@ -308,6 +347,20 @@ std::vector<std::size_t> getEdgeIndex(const std::vector<RTreeLeaf> &edges)
|
||||
return sorted_edge_indexes;
|
||||
}
|
||||
|
||||
std::vector<NodeID> getSegregatedNodes(const DataFacadeBase &facade,
|
||||
const std::vector<RTreeLeaf> &edges)
|
||||
{
|
||||
std::vector<NodeID> result;
|
||||
|
||||
for (RTreeLeaf const &e : edges)
|
||||
{
|
||||
if (e.forward_segment_id.enabled && facade.IsSegregated(e.forward_segment_id.id))
|
||||
result.push_back(e.forward_segment_id.id);
|
||||
}
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
void encodeVectorTile(const DataFacadeBase &facade,
|
||||
unsigned x,
|
||||
unsigned y,
|
||||
@@ -315,6 +368,7 @@ void encodeVectorTile(const DataFacadeBase &facade,
|
||||
const std::vector<RTreeLeaf> &edges,
|
||||
const std::vector<std::size_t> &sorted_edge_indexes,
|
||||
const std::vector<routing_algorithms::TurnData> &all_turn_data,
|
||||
const std::vector<NodeID> &segregated_nodes,
|
||||
std::string &pbf_buffer)
|
||||
{
|
||||
|
||||
@@ -712,10 +766,10 @@ void encodeVectorTile(const DataFacadeBase &facade,
|
||||
point_float_index.add(t.weight / 10.0); // Note conversion to float here
|
||||
|
||||
auto turntype_idx =
|
||||
point_string_index.add(api::json::detail::internalInstructionTypeToString(
|
||||
point_string_index.add(extractor::guidance::internalInstructionTypeToString(
|
||||
t.turn_instruction.type));
|
||||
auto turnmodifier_idx =
|
||||
point_string_index.add(api::json::detail::instructionModifierToString(
|
||||
point_string_index.add(extractor::guidance::instructionModifierToString(
|
||||
t.turn_instruction.direction_modifier));
|
||||
return EncodedTurnData{t.coordinate,
|
||||
angle_idx,
|
||||
@@ -865,6 +919,66 @@ void encodeVectorTile(const DataFacadeBase &facade,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
{
|
||||
protozero::pbf_writer line_layer_writer(tile_writer, util::vector_tile::LAYER_TAG);
|
||||
line_layer_writer.add_uint32(util::vector_tile::VERSION_TAG, 2); // version
|
||||
line_layer_writer.add_string(util::vector_tile::NAME_TAG, "internal-nodes"); // name
|
||||
line_layer_writer.add_uint32(util::vector_tile::EXTENT_TAG,
|
||||
util::vector_tile::EXTENT); // extent
|
||||
|
||||
unsigned id = 0;
|
||||
for (auto edgeNodeID : segregated_nodes)
|
||||
{
|
||||
auto const geomIndex = facade.GetGeometryIndex(edgeNodeID);
|
||||
std::vector<NodeID> geometry;
|
||||
|
||||
if (geomIndex.forward)
|
||||
geometry = facade.GetUncompressedForwardGeometry(geomIndex.id);
|
||||
else
|
||||
geometry = facade.GetUncompressedReverseGeometry(geomIndex.id);
|
||||
|
||||
std::vector<util::Coordinate> points;
|
||||
for (auto const nodeID : geometry)
|
||||
points.push_back(facade.GetCoordinateOfNode(nodeID));
|
||||
|
||||
const auto encode_tile_line = [&line_layer_writer, &id](
|
||||
const FixedLine &tile_line, std::int32_t &start_x, std::int32_t &start_y) {
|
||||
|
||||
protozero::pbf_writer feature_writer(line_layer_writer,
|
||||
util::vector_tile::FEATURE_TAG);
|
||||
|
||||
feature_writer.add_enum(util::vector_tile::GEOMETRY_TAG,
|
||||
util::vector_tile::GEOMETRY_TYPE_LINE); // geometry type
|
||||
|
||||
feature_writer.add_uint64(util::vector_tile::ID_TAG, id++); // id
|
||||
{
|
||||
|
||||
protozero::packed_field_uint32 field(
|
||||
feature_writer, util::vector_tile::FEATURE_ATTRIBUTES_TAG);
|
||||
}
|
||||
{
|
||||
|
||||
// Encode the geometry for the feature
|
||||
protozero::packed_field_uint32 geometry(
|
||||
feature_writer, util::vector_tile::FEATURE_GEOMETRIES_TAG);
|
||||
encodeLinestring(tile_line, geometry, start_x, start_y);
|
||||
}
|
||||
};
|
||||
|
||||
std::int32_t start_x = 0;
|
||||
std::int32_t start_y = 0;
|
||||
|
||||
auto tile_lines = coordinatesToTileLine(points, tile_bbox);
|
||||
if (!tile_lines.empty())
|
||||
{
|
||||
for (auto const &tl : tile_lines)
|
||||
{
|
||||
encode_tile_line(tl, start_x, start_y);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
// protozero serializes data during object destructors, so once the scope closes,
|
||||
// our result buffer will have all the tile data encoded into it.
|
||||
@@ -879,6 +993,7 @@ Status TilePlugin::HandleRequest(const RoutingAlgorithmsInterface &algorithms,
|
||||
|
||||
const auto &facade = algorithms.GetFacade();
|
||||
auto edges = getEdges(facade, parameters.x, parameters.y, parameters.z);
|
||||
auto segregated_nodes = getSegregatedNodes(facade, edges);
|
||||
|
||||
auto edge_index = getEdgeIndex(edges);
|
||||
|
||||
@@ -891,8 +1006,15 @@ Status TilePlugin::HandleRequest(const RoutingAlgorithmsInterface &algorithms,
|
||||
turns = algorithms.GetTileTurns(edges, edge_index);
|
||||
}
|
||||
|
||||
encodeVectorTile(
|
||||
facade, parameters.x, parameters.y, parameters.z, edges, edge_index, turns, pbf_buffer);
|
||||
encodeVectorTile(facade,
|
||||
parameters.x,
|
||||
parameters.y,
|
||||
parameters.z,
|
||||
edges,
|
||||
edge_index,
|
||||
turns,
|
||||
segregated_nodes,
|
||||
pbf_buffer);
|
||||
|
||||
return Status::Ok;
|
||||
}
|
||||
|
||||
@@ -233,6 +233,12 @@ RandIt filterPackedPathsByCellSharing(RandIt first, RandIt last, const Partition
|
||||
cells.insert(get_cell(std::get<1>(edge)));
|
||||
|
||||
const auto over_sharing_limit = [&](const auto &packed) {
|
||||
|
||||
if (packed.path.empty())
|
||||
{ // don't remove routes with single-node (empty) path
|
||||
return false;
|
||||
}
|
||||
|
||||
const auto not_seen = [&](const PackedEdge edge) {
|
||||
const auto source_cell = get_cell(std::get<0>(edge));
|
||||
const auto target_cell = get_cell(std::get<1>(edge));
|
||||
@@ -310,7 +316,7 @@ RandIt filterPackedPathsByLocalOptimality(const WeightedViaNodePackedPath &path,
|
||||
// Check plateaux edges towards the target. Terminates at the source / target
|
||||
// at the latest, since parent(target)==target for the reverse heap and
|
||||
// parent(target) != target in the forward heap (and vice versa).
|
||||
while (has_plateaux_at_node(node, fst, snd))
|
||||
while (node != fst.GetData(node).parent && has_plateaux_at_node(node, fst, snd))
|
||||
node = fst.GetData(node).parent;
|
||||
|
||||
return node;
|
||||
@@ -320,7 +326,11 @@ RandIt filterPackedPathsByLocalOptimality(const WeightedViaNodePackedPath &path,
|
||||
BOOST_ASSERT(packed.via.node != path.via.node);
|
||||
BOOST_ASSERT(packed.via.weight != INVALID_EDGE_WEIGHT);
|
||||
BOOST_ASSERT(packed.via.node != SPECIAL_NODEID);
|
||||
BOOST_ASSERT(!packed.path.empty());
|
||||
|
||||
if (packed.path.empty())
|
||||
{ // the edge case when packed.via.node is both source and target node
|
||||
return false;
|
||||
}
|
||||
|
||||
const NodeID via = packed.via.node;
|
||||
|
||||
@@ -395,6 +405,12 @@ template <typename RandIt> RandIt filterUnpackedPathsBySharing(RandIt first, Ran
|
||||
edges.insert(begin(shortest_path.edges), begin(shortest_path.edges));
|
||||
|
||||
const auto over_sharing_limit = [&](const auto &unpacked) {
|
||||
|
||||
if (unpacked.edges.empty())
|
||||
{ // don't remove routes with single-node (empty) path
|
||||
return false;
|
||||
}
|
||||
|
||||
const auto not_seen = [&](const EdgeID edge) { return edges.count(edge) < 1; };
|
||||
const auto different = std::count_if(begin(unpacked.edges), end(unpacked.edges), not_seen);
|
||||
|
||||
|
||||
@@ -67,12 +67,13 @@ EdgeBasedGraphFactory::EdgeBasedGraphFactory(
|
||||
const std::unordered_set<NodeID> &traffic_lights,
|
||||
const std::vector<util::Coordinate> &coordinates,
|
||||
const util::NameTable &name_table,
|
||||
const std::unordered_set<EdgeID> &segregated_edges,
|
||||
guidance::LaneDescriptionMap &lane_description_map)
|
||||
: m_edge_based_node_container(node_data_container), m_number_of_edge_based_nodes(0),
|
||||
m_coordinates(coordinates), m_node_based_graph(std::move(node_based_graph)),
|
||||
m_barrier_nodes(barrier_nodes), m_traffic_lights(traffic_lights),
|
||||
m_compressed_edge_container(compressed_edge_container), name_table(name_table),
|
||||
lane_description_map(lane_description_map)
|
||||
segregated_edges(segregated_edges), lane_description_map(lane_description_map)
|
||||
{
|
||||
}
|
||||
|
||||
@@ -164,13 +165,19 @@ NBGToEBG EdgeBasedGraphFactory::InsertEdgeBasedNode(const NodeID node_u, const N
|
||||
forward_data.geometry_id;
|
||||
m_edge_based_node_container.nodes[nbe_to_ebn_mapping[edge_id_1]].annotation_id =
|
||||
forward_data.annotation_data;
|
||||
m_edge_based_node_container.nodes[nbe_to_ebn_mapping[edge_id_1]].segregated =
|
||||
segregated_edges.count(edge_id_1) > 0;
|
||||
|
||||
if (nbe_to_ebn_mapping[edge_id_2] != SPECIAL_EDGEID)
|
||||
{
|
||||
m_edge_based_node_container.nodes[nbe_to_ebn_mapping[edge_id_2]].geometry_id =
|
||||
reverse_data.geometry_id;
|
||||
m_edge_based_node_container.nodes[nbe_to_ebn_mapping[edge_id_2]].annotation_id =
|
||||
reverse_data.annotation_data;
|
||||
m_edge_based_node_container.nodes[nbe_to_ebn_mapping[edge_id_2]].segregated =
|
||||
segregated_edges.count(edge_id_2) > 0;
|
||||
}
|
||||
|
||||
// Add segments of edge-based nodes
|
||||
for (const auto i : util::irange(std::size_t{0}, segment_count))
|
||||
{
|
||||
@@ -365,6 +372,8 @@ EdgeBasedGraphFactory::GenerateEdgeExpandedNodes(const WayRestrictionMap &way_re
|
||||
edge_data.geometry_id;
|
||||
m_edge_based_node_container.nodes[edge_based_node_id].annotation_id =
|
||||
edge_data.annotation_data;
|
||||
m_edge_based_node_container.nodes[edge_based_node_id].segregated =
|
||||
segregated_edges.count(eid) > 0;
|
||||
|
||||
m_edge_based_node_weights.push_back(m_edge_based_node_weights[eid]);
|
||||
|
||||
@@ -569,12 +578,16 @@ void EdgeBasedGraphFactory::GenerateEdgeExpandedEdges(
|
||||
// compute weight and duration penalties
|
||||
auto is_traffic_light = m_traffic_lights.count(node_at_center_of_intersection);
|
||||
ExtractionTurn extracted_turn(
|
||||
turn,
|
||||
turn.angle,
|
||||
m_node_based_graph.GetOutDegree(node_at_center_of_intersection),
|
||||
turn.instruction.direction_modifier == guidance::DirectionModifier::UTurn,
|
||||
is_traffic_light,
|
||||
edge_data1.flags.restricted,
|
||||
edge_data2.flags.restricted,
|
||||
m_edge_based_node_container.GetAnnotation(edge_data1.annotation_data)
|
||||
.is_left_hand_driving);
|
||||
.is_left_hand_driving,
|
||||
m_edge_based_node_container.GetAnnotation(edge_data1.annotation_data).travel_mode,
|
||||
m_edge_based_node_container.GetAnnotation(edge_data2.annotation_data).travel_mode);
|
||||
scripting_environment.ProcessTurn(extracted_turn);
|
||||
|
||||
// turn penalties are limited to [-2^15, 2^15) which roughly
|
||||
|
||||
@@ -217,6 +217,15 @@ int Extractor::run(ScriptingEnvironment &scripting_environment)
|
||||
turn_restrictions,
|
||||
conditional_turn_restrictions);
|
||||
|
||||
util::Log() << "Find segregated edges in node-based graph ..." << std::flush;
|
||||
TIMER_START(segregated);
|
||||
|
||||
auto segregated_edges = FindSegregatedNodes(node_based_graph_factory);
|
||||
|
||||
TIMER_STOP(segregated);
|
||||
util::Log() << "ok, after " << TIMER_SEC(segregated) << "s";
|
||||
util::Log() << "Segregated edges count = " << segregated_edges.size();
|
||||
|
||||
util::Log() << "Writing nodes for nodes-based and edges-based graphs ...";
|
||||
auto const &coordinates = node_based_graph_factory.GetCoordinates();
|
||||
files::writeNodes(
|
||||
@@ -268,6 +277,7 @@ int Extractor::run(ScriptingEnvironment &scripting_environment)
|
||||
traffic_signals,
|
||||
turn_restrictions,
|
||||
conditional_turn_restrictions,
|
||||
segregated_edges,
|
||||
turn_lane_map,
|
||||
scripting_environment,
|
||||
edge_based_nodes_container,
|
||||
@@ -655,6 +665,7 @@ EdgeID Extractor::BuildEdgeExpandedGraph(
|
||||
const std::unordered_set<NodeID> &traffic_signals,
|
||||
const std::vector<TurnRestriction> &turn_restrictions,
|
||||
const std::vector<ConditionalTurnRestriction> &conditional_turn_restrictions,
|
||||
const std::unordered_set<EdgeID> &segregated_edges,
|
||||
// might have to be updated to add new lane combinations
|
||||
guidance::LaneDescriptionMap &turn_lane_map,
|
||||
// for calculating turn penalties
|
||||
@@ -676,6 +687,7 @@ EdgeID Extractor::BuildEdgeExpandedGraph(
|
||||
traffic_signals,
|
||||
coordinates,
|
||||
name_table,
|
||||
segregated_edges,
|
||||
turn_lane_map);
|
||||
|
||||
const auto create_edge_based_edges = [&]() {
|
||||
@@ -826,5 +838,232 @@ void Extractor::WriteCompressedNodeBasedGraph(const std::string &path,
|
||||
}
|
||||
}
|
||||
|
||||
struct EdgeInfo
|
||||
{
|
||||
NodeID node;
|
||||
|
||||
util::StringView name;
|
||||
|
||||
// 0 - outgoing (forward), 1 - incoming (reverse), 2 - both outgoing and incoming
|
||||
int direction;
|
||||
|
||||
ClassData road_class;
|
||||
|
||||
guidance::RoadPriorityClass::Enum road_priority_class;
|
||||
|
||||
struct LessName
|
||||
{
|
||||
bool operator()(EdgeInfo const &e1, EdgeInfo const &e2) const { return e1.name < e2.name; }
|
||||
};
|
||||
};
|
||||
|
||||
bool IsSegregated(std::vector<EdgeInfo> v1,
|
||||
std::vector<EdgeInfo> v2,
|
||||
EdgeInfo const ¤t,
|
||||
double edgeLength)
|
||||
{
|
||||
if (v1.size() < 2 || v2.size() < 2)
|
||||
return false;
|
||||
|
||||
auto const sort_by_name_fn = [](std::vector<EdgeInfo> &v) {
|
||||
std::sort(v.begin(), v.end(), EdgeInfo::LessName());
|
||||
};
|
||||
|
||||
sort_by_name_fn(v1);
|
||||
sort_by_name_fn(v2);
|
||||
|
||||
// Internal edge with the name should be connected with any other neibour edge with the same
|
||||
// name, e.g. isolated edge with unique name is not segregated.
|
||||
// b - 'b' road continues here
|
||||
// |
|
||||
// - - a - |
|
||||
// b - segregated edge
|
||||
// - - a - |
|
||||
if (!current.name.empty())
|
||||
{
|
||||
auto const findNameFn = [¤t](std::vector<EdgeInfo> const &v) {
|
||||
return std::binary_search(v.begin(), v.end(), current, EdgeInfo::LessName());
|
||||
};
|
||||
|
||||
if (!findNameFn(v1) && !findNameFn(v2))
|
||||
return false;
|
||||
}
|
||||
|
||||
// set_intersection like routine to get equal result pairs
|
||||
std::vector<std::pair<EdgeInfo const *, EdgeInfo const *>> commons;
|
||||
|
||||
auto i1 = v1.begin();
|
||||
auto i2 = v2.begin();
|
||||
|
||||
while (i1 != v1.end() && i2 != v2.end())
|
||||
{
|
||||
if (i1->name == i2->name)
|
||||
{
|
||||
if (!i1->name.empty())
|
||||
commons.push_back(std::make_pair(&(*i1), &(*i2)));
|
||||
|
||||
++i1;
|
||||
++i2;
|
||||
}
|
||||
else if (i1->name < i2->name)
|
||||
++i1;
|
||||
else
|
||||
++i2;
|
||||
}
|
||||
|
||||
if (commons.size() < 2)
|
||||
return false;
|
||||
|
||||
auto const check_equal_class = [](std::pair<EdgeInfo const *, EdgeInfo const *> const &e) {
|
||||
// Or (e.first->road_class & e.second->road_class != 0)
|
||||
return e.first->road_class == e.second->road_class;
|
||||
};
|
||||
|
||||
size_t equal_class_count = 0;
|
||||
for (auto const &e : commons)
|
||||
if (check_equal_class(e))
|
||||
++equal_class_count;
|
||||
|
||||
if (equal_class_count < 2)
|
||||
return false;
|
||||
|
||||
auto const get_length_threshold = [](EdgeInfo const *e) {
|
||||
switch (e->road_priority_class)
|
||||
{
|
||||
case guidance::RoadPriorityClass::MOTORWAY:
|
||||
case guidance::RoadPriorityClass::TRUNK:
|
||||
return 30.0;
|
||||
case guidance::RoadPriorityClass::PRIMARY:
|
||||
return 20.0;
|
||||
case guidance::RoadPriorityClass::SECONDARY:
|
||||
case guidance::RoadPriorityClass::TERTIARY:
|
||||
return 10.0;
|
||||
default:
|
||||
return 5.0;
|
||||
}
|
||||
};
|
||||
|
||||
double threshold = std::numeric_limits<double>::max();
|
||||
for (auto const &e : commons)
|
||||
threshold =
|
||||
std::min(threshold, get_length_threshold(e.first) + get_length_threshold(e.second));
|
||||
|
||||
return edgeLength <= threshold;
|
||||
}
|
||||
|
||||
std::unordered_set<EdgeID> Extractor::FindSegregatedNodes(NodeBasedGraphFactory &factory)
|
||||
{
|
||||
util::NameTable names(config.GetPath(".osrm.names").string());
|
||||
|
||||
auto const &graph = factory.GetGraph();
|
||||
auto const &annotation = factory.GetAnnotationData();
|
||||
|
||||
guidance::CoordinateExtractor coordExtractor(
|
||||
graph, factory.GetCompressedEdges(), factory.GetCoordinates());
|
||||
|
||||
auto const get_edge_length = [&](NodeID from_node, EdgeID edgeID, NodeID to_node) {
|
||||
auto const geom = coordExtractor.GetCoordinatesAlongRoad(from_node, edgeID, false, to_node);
|
||||
double length = 0.0;
|
||||
for (size_t i = 1; i < geom.size(); ++i)
|
||||
{
|
||||
length += osrm::util::coordinate_calculation::haversineDistance(geom[i - 1], geom[i]);
|
||||
}
|
||||
return length;
|
||||
};
|
||||
|
||||
auto const get_edge_info = [&](NodeID node, auto const &edgeData) -> EdgeInfo {
|
||||
/// @todo Make string normalization/lowercase/trim for comparison ...
|
||||
|
||||
auto const id = annotation[edgeData.annotation_data].name_id;
|
||||
BOOST_ASSERT(id != INVALID_NAMEID);
|
||||
auto const name = names.GetNameForID(id);
|
||||
|
||||
return {node,
|
||||
name,
|
||||
edgeData.reversed ? 1 : 0,
|
||||
annotation[edgeData.annotation_data].classes,
|
||||
edgeData.flags.road_classification.GetClass()};
|
||||
};
|
||||
|
||||
auto const collect_edge_info_fn = [&](auto const &edges1, NodeID node2) {
|
||||
std::vector<EdgeInfo> info;
|
||||
|
||||
for (auto const &e : edges1)
|
||||
{
|
||||
NodeID const target = graph.GetTarget(e);
|
||||
if (target == node2)
|
||||
continue;
|
||||
|
||||
info.push_back(get_edge_info(target, graph.GetEdgeData(e)));
|
||||
}
|
||||
|
||||
if (info.empty())
|
||||
return info;
|
||||
|
||||
std::sort(info.begin(), info.end(), [](EdgeInfo const &e1, EdgeInfo const &e2) {
|
||||
return e1.node < e2.node;
|
||||
});
|
||||
|
||||
// Merge equal infos with correct direction.
|
||||
auto curr = info.begin();
|
||||
auto next = curr;
|
||||
while (++next != info.end())
|
||||
{
|
||||
if (curr->node == next->node)
|
||||
{
|
||||
BOOST_ASSERT(curr->name == next->name);
|
||||
BOOST_ASSERT(curr->road_class == next->road_class);
|
||||
BOOST_ASSERT(curr->direction != next->direction);
|
||||
curr->direction = 2;
|
||||
}
|
||||
else
|
||||
curr = next;
|
||||
}
|
||||
|
||||
info.erase(
|
||||
std::unique(info.begin(),
|
||||
info.end(),
|
||||
[](EdgeInfo const &e1, EdgeInfo const &e2) { return e1.node == e2.node; }),
|
||||
info.end());
|
||||
|
||||
return info;
|
||||
};
|
||||
|
||||
auto const isSegregatedFn = [&](auto const &edgeData,
|
||||
auto const &edges1,
|
||||
NodeID node1,
|
||||
auto const &edges2,
|
||||
NodeID node2,
|
||||
double edgeLength) {
|
||||
return IsSegregated(collect_edge_info_fn(edges1, node2),
|
||||
collect_edge_info_fn(edges2, node1),
|
||||
get_edge_info(node1, edgeData),
|
||||
edgeLength);
|
||||
};
|
||||
|
||||
std::unordered_set<EdgeID> segregated_edges;
|
||||
|
||||
for (NodeID sourceID = 0; sourceID < graph.GetNumberOfNodes(); ++sourceID)
|
||||
{
|
||||
auto const sourceEdges = graph.GetAdjacentEdgeRange(sourceID);
|
||||
for (EdgeID edgeID : sourceEdges)
|
||||
{
|
||||
auto const &edgeData = graph.GetEdgeData(edgeID);
|
||||
|
||||
if (edgeData.reversed)
|
||||
continue;
|
||||
|
||||
NodeID const targetID = graph.GetTarget(edgeID);
|
||||
auto const targetEdges = graph.GetAdjacentEdgeRange(targetID);
|
||||
|
||||
double const length = get_edge_length(sourceID, edgeID, targetID);
|
||||
if (isSegregatedFn(edgeData, sourceEdges, sourceID, targetEdges, targetID, length))
|
||||
segregated_edges.insert(edgeID);
|
||||
}
|
||||
}
|
||||
|
||||
return segregated_edges;
|
||||
}
|
||||
|
||||
} // namespace extractor
|
||||
} // namespace osrm
|
||||
|
||||
@@ -90,18 +90,19 @@ void ExtractorCallbacks::ProcessRestriction(const InputConditionalTurnRestrictio
|
||||
*/
|
||||
void ExtractorCallbacks::ProcessWay(const osmium::Way &input_way, const ExtractionWay &parsed_way)
|
||||
{
|
||||
if ((parsed_way.forward_travel_mode == TRAVEL_MODE_INACCESSIBLE ||
|
||||
if ((parsed_way.forward_travel_mode == extractor::TRAVEL_MODE_INACCESSIBLE ||
|
||||
parsed_way.forward_speed <= 0) &&
|
||||
(parsed_way.backward_travel_mode == TRAVEL_MODE_INACCESSIBLE ||
|
||||
(parsed_way.backward_travel_mode == extractor::TRAVEL_MODE_INACCESSIBLE ||
|
||||
parsed_way.backward_speed <= 0) &&
|
||||
parsed_way.duration <= 0)
|
||||
{ // Only true if the way is assigned a valid speed/duration
|
||||
return;
|
||||
}
|
||||
|
||||
if (!fallback_to_duration && (parsed_way.forward_travel_mode == TRAVEL_MODE_INACCESSIBLE ||
|
||||
parsed_way.forward_rate <= 0) &&
|
||||
(parsed_way.backward_travel_mode == TRAVEL_MODE_INACCESSIBLE ||
|
||||
if (!fallback_to_duration &&
|
||||
(parsed_way.forward_travel_mode == extractor::TRAVEL_MODE_INACCESSIBLE ||
|
||||
parsed_way.forward_rate <= 0) &&
|
||||
(parsed_way.backward_travel_mode == extractor::TRAVEL_MODE_INACCESSIBLE ||
|
||||
parsed_way.backward_rate <= 0) &&
|
||||
parsed_way.weight <= 0)
|
||||
{ // Only true if the way is assigned a valid rate/weight and there is no duration fallback
|
||||
@@ -145,7 +146,7 @@ void ExtractorCallbacks::ProcessWay(const osmium::Way &input_way, const Extracti
|
||||
}
|
||||
};
|
||||
|
||||
if (parsed_way.forward_travel_mode != TRAVEL_MODE_INACCESSIBLE)
|
||||
if (parsed_way.forward_travel_mode != extractor::TRAVEL_MODE_INACCESSIBLE)
|
||||
{
|
||||
BOOST_ASSERT(parsed_way.duration > 0 || parsed_way.forward_speed > 0);
|
||||
forward_duration_data =
|
||||
@@ -162,7 +163,7 @@ void ExtractorCallbacks::ProcessWay(const osmium::Way &input_way, const Extracti
|
||||
toValueByEdgeOrByMeter(parsed_way.weight, parsed_way.forward_rate);
|
||||
}
|
||||
}
|
||||
if (parsed_way.backward_travel_mode != TRAVEL_MODE_INACCESSIBLE)
|
||||
if (parsed_way.backward_travel_mode != extractor::TRAVEL_MODE_INACCESSIBLE)
|
||||
{
|
||||
BOOST_ASSERT(parsed_way.duration > 0 || parsed_way.backward_speed > 0);
|
||||
backward_duration_data =
|
||||
@@ -318,67 +319,74 @@ void ExtractorCallbacks::ProcessWay(const osmium::Way &input_way, const Extracti
|
||||
road_classification.SetNumberOfLanes(std::max(road_deduced_num_lanes, // len(turn:lanes)
|
||||
road_classification.GetNumberOfLanes()));
|
||||
|
||||
// Get the unique identifier for the street name, destination, and ref
|
||||
const auto name_iterator = string_map.find(MapKey(parsed_way.name,
|
||||
parsed_way.destinations,
|
||||
parsed_way.ref,
|
||||
parsed_way.pronunciation,
|
||||
parsed_way.exits));
|
||||
NameID name_id = EMPTY_NAMEID;
|
||||
if (string_map.end() == name_iterator)
|
||||
{
|
||||
// name_offsets has a sentinel element with the total name data size
|
||||
// take the sentinels index as the name id of the new name data pack
|
||||
// (name [name_id], destination [+1], pronunciation [+2], ref [+3], exits [+4])
|
||||
name_id = external_memory.name_offsets.size() - 1;
|
||||
const auto GetNameID = [this, &parsed_way](bool is_forward) -> NameID {
|
||||
const std::string &ref = is_forward ? parsed_way.forward_ref : parsed_way.backward_ref;
|
||||
// Get the unique identifier for the street name, destination, and ref
|
||||
const auto name_iterator = string_map.find(MapKey(parsed_way.name,
|
||||
parsed_way.destinations,
|
||||
ref,
|
||||
parsed_way.pronunciation,
|
||||
parsed_way.exits));
|
||||
|
||||
std::copy(parsed_way.name.begin(),
|
||||
parsed_way.name.end(),
|
||||
std::back_inserter(external_memory.name_char_data));
|
||||
external_memory.name_offsets.push_back(external_memory.name_char_data.size());
|
||||
NameID name_id = EMPTY_NAMEID;
|
||||
if (string_map.end() == name_iterator)
|
||||
{
|
||||
// name_offsets has a sentinel element with the total name data size
|
||||
// take the sentinels index as the name id of the new name data pack
|
||||
// (name [name_id], destination [+1], pronunciation [+2], ref [+3], exits [+4])
|
||||
name_id = external_memory.name_offsets.size() - 1;
|
||||
|
||||
std::copy(parsed_way.destinations.begin(),
|
||||
parsed_way.destinations.end(),
|
||||
std::back_inserter(external_memory.name_char_data));
|
||||
external_memory.name_offsets.push_back(external_memory.name_char_data.size());
|
||||
std::copy(parsed_way.name.begin(),
|
||||
parsed_way.name.end(),
|
||||
std::back_inserter(external_memory.name_char_data));
|
||||
external_memory.name_offsets.push_back(external_memory.name_char_data.size());
|
||||
|
||||
std::copy(parsed_way.pronunciation.begin(),
|
||||
parsed_way.pronunciation.end(),
|
||||
std::back_inserter(external_memory.name_char_data));
|
||||
external_memory.name_offsets.push_back(external_memory.name_char_data.size());
|
||||
std::copy(parsed_way.destinations.begin(),
|
||||
parsed_way.destinations.end(),
|
||||
std::back_inserter(external_memory.name_char_data));
|
||||
external_memory.name_offsets.push_back(external_memory.name_char_data.size());
|
||||
|
||||
std::copy(parsed_way.ref.begin(),
|
||||
parsed_way.ref.end(),
|
||||
std::back_inserter(external_memory.name_char_data));
|
||||
external_memory.name_offsets.push_back(external_memory.name_char_data.size());
|
||||
std::copy(parsed_way.pronunciation.begin(),
|
||||
parsed_way.pronunciation.end(),
|
||||
std::back_inserter(external_memory.name_char_data));
|
||||
external_memory.name_offsets.push_back(external_memory.name_char_data.size());
|
||||
|
||||
std::copy(parsed_way.exits.begin(),
|
||||
parsed_way.exits.end(),
|
||||
std::back_inserter(external_memory.name_char_data));
|
||||
external_memory.name_offsets.push_back(external_memory.name_char_data.size());
|
||||
std::copy(ref.begin(), ref.end(), std::back_inserter(external_memory.name_char_data));
|
||||
external_memory.name_offsets.push_back(external_memory.name_char_data.size());
|
||||
|
||||
auto k = MapKey{parsed_way.name,
|
||||
parsed_way.destinations,
|
||||
parsed_way.ref,
|
||||
parsed_way.pronunciation,
|
||||
parsed_way.exits};
|
||||
auto v = MapVal{name_id};
|
||||
string_map.emplace(std::move(k), std::move(v));
|
||||
}
|
||||
else
|
||||
{
|
||||
name_id = name_iterator->second;
|
||||
}
|
||||
std::copy(parsed_way.exits.begin(),
|
||||
parsed_way.exits.end(),
|
||||
std::back_inserter(external_memory.name_char_data));
|
||||
external_memory.name_offsets.push_back(external_memory.name_char_data.size());
|
||||
|
||||
auto k = MapKey{parsed_way.name,
|
||||
parsed_way.destinations,
|
||||
ref,
|
||||
parsed_way.pronunciation,
|
||||
parsed_way.exits};
|
||||
auto v = MapVal{name_id};
|
||||
string_map.emplace(std::move(k), std::move(v));
|
||||
}
|
||||
else
|
||||
{
|
||||
name_id = name_iterator->second;
|
||||
}
|
||||
|
||||
return name_id;
|
||||
};
|
||||
|
||||
const NameID forward_name_id = GetNameID(true);
|
||||
const NameID backward_name_id = GetNameID(false);
|
||||
|
||||
const bool in_forward_direction =
|
||||
(parsed_way.forward_speed > 0 || parsed_way.forward_rate > 0 || parsed_way.duration > 0 ||
|
||||
parsed_way.weight > 0) &&
|
||||
(parsed_way.forward_travel_mode != TRAVEL_MODE_INACCESSIBLE);
|
||||
(parsed_way.forward_travel_mode != extractor::TRAVEL_MODE_INACCESSIBLE);
|
||||
|
||||
const bool in_backward_direction =
|
||||
(parsed_way.backward_speed > 0 || parsed_way.backward_rate > 0 || parsed_way.duration > 0 ||
|
||||
parsed_way.weight > 0) &&
|
||||
(parsed_way.backward_travel_mode != TRAVEL_MODE_INACCESSIBLE);
|
||||
(parsed_way.backward_travel_mode != extractor::TRAVEL_MODE_INACCESSIBLE);
|
||||
|
||||
// split an edge into two edges if forwards/backwards behavior differ
|
||||
const bool split_edge =
|
||||
@@ -386,12 +394,13 @@ void ExtractorCallbacks::ProcessWay(const osmium::Way &input_way, const Extracti
|
||||
(force_split_edges || (parsed_way.forward_rate != parsed_way.backward_rate) ||
|
||||
(parsed_way.forward_speed != parsed_way.backward_speed) ||
|
||||
(parsed_way.forward_travel_mode != parsed_way.backward_travel_mode) ||
|
||||
(turn_lane_id_forward != turn_lane_id_backward) || (forward_classes != backward_classes));
|
||||
(turn_lane_id_forward != turn_lane_id_backward) || (forward_classes != backward_classes) ||
|
||||
(parsed_way.forward_ref != parsed_way.backward_ref));
|
||||
|
||||
if (in_forward_direction)
|
||||
{ // add (forward) segments or (forward,backward) for non-split edges in backward direction
|
||||
const auto annotation_data_id = external_memory.all_edges_annotation_data_list.size();
|
||||
external_memory.all_edges_annotation_data_list.push_back({name_id,
|
||||
external_memory.all_edges_annotation_data_list.push_back({forward_name_id,
|
||||
turn_lane_id_forward,
|
||||
forward_classes,
|
||||
parsed_way.forward_travel_mode,
|
||||
@@ -424,7 +433,7 @@ void ExtractorCallbacks::ProcessWay(const osmium::Way &input_way, const Extracti
|
||||
if (in_backward_direction && (!in_forward_direction || split_edge))
|
||||
{ // add (backward) segments for split edges or not in forward direction
|
||||
const auto annotation_data_id = external_memory.all_edges_annotation_data_list.size();
|
||||
external_memory.all_edges_annotation_data_list.push_back({name_id,
|
||||
external_memory.all_edges_annotation_data_list.push_back({backward_name_id,
|
||||
turn_lane_id_backward,
|
||||
backward_classes,
|
||||
parsed_way.backward_travel_mode,
|
||||
|
||||
@@ -221,10 +221,15 @@ void GraphCompressor::Compress(
|
||||
|
||||
// generate an artifical turn for the turn penalty generation
|
||||
ExtractionTurn extraction_turn(
|
||||
0,
|
||||
2,
|
||||
false,
|
||||
true,
|
||||
fwd_edge_data1.flags.restricted,
|
||||
fwd_edge_data2.flags.restricted,
|
||||
node_data_container[fwd_edge_data1.annotation_data].is_left_hand_driving);
|
||||
node_data_container[fwd_edge_data1.annotation_data].is_left_hand_driving,
|
||||
TRAVEL_MODE_DRIVING,
|
||||
TRAVEL_MODE_DRIVING);
|
||||
|
||||
scripting_environment.ProcessTurn(extraction_turn);
|
||||
node_duration_penalty = extraction_turn.duration * 10;
|
||||
|
||||
@@ -370,6 +370,17 @@ IntersectionNormalizer::AdjustBearingsForMergeAtDestination(const NodeID node_at
|
||||
: offset;
|
||||
};
|
||||
|
||||
// only if straighmost angles get smaller, we consider it an improvement
|
||||
auto const improves_straightmost = [&](auto const index, auto const offset) {
|
||||
const auto itr = next_intersection_along_road.FindClosestBearing(
|
||||
util::bearing::reverse(next_intersection_along_road[index].bearing));
|
||||
const auto angle = util::bearing::angleBetween(
|
||||
util::bearing::reverse(itr->bearing), next_intersection_along_road[index].bearing);
|
||||
|
||||
return util::angularDeviation(angle, STRAIGHT_ANGLE) >
|
||||
util::angularDeviation(angle + offset, STRAIGHT_ANGLE);
|
||||
};
|
||||
|
||||
// check if the u-turn edge at the next intersection could be merged to the left/right. If
|
||||
// this is the case and the road is not far away (see previous distance check), if
|
||||
// influences the perceived angle.
|
||||
@@ -378,13 +389,17 @@ IntersectionNormalizer::AdjustBearingsForMergeAtDestination(const NodeID node_at
|
||||
const auto offset =
|
||||
get_offset(next_intersection_along_road[0], next_intersection_along_road[1]);
|
||||
|
||||
const auto corrected_offset = get_corrected_offset(
|
||||
offset,
|
||||
road,
|
||||
intersection[(intersection.size() + index - 1) % intersection.size()]);
|
||||
// at the target intersection, we merge to the right, so we need to shift the current
|
||||
// angle to the left
|
||||
road.bearing = adjustAngle(road.bearing, corrected_offset);
|
||||
if (improves_straightmost(0, -offset) && improves_straightmost(1, offset))
|
||||
{
|
||||
const auto corrected_offset = get_corrected_offset(
|
||||
offset,
|
||||
road,
|
||||
intersection[(intersection.size() + index - 1) % intersection.size()]);
|
||||
// at the target intersection, we merge to the right, so we need to shift the
|
||||
// current
|
||||
// angle to the left
|
||||
road.bearing = adjustAngle(road.bearing, corrected_offset);
|
||||
}
|
||||
}
|
||||
else if (CanMerge(node_at_next_intersection,
|
||||
next_intersection_along_road,
|
||||
@@ -395,13 +410,18 @@ IntersectionNormalizer::AdjustBearingsForMergeAtDestination(const NodeID node_at
|
||||
get_offset(next_intersection_along_road[0],
|
||||
next_intersection_along_road[next_intersection_along_road.size() - 1]);
|
||||
|
||||
const auto corrected_offset =
|
||||
get_corrected_offset(offset, road, intersection[(index + 1) % intersection.size()]);
|
||||
// at the target intersection, we merge to the left, so we need to shift the current
|
||||
// angle to the right
|
||||
road.bearing = adjustAngle(road.bearing, -corrected_offset);
|
||||
if (improves_straightmost(0, offset) &&
|
||||
improves_straightmost(next_intersection_along_road.size() - 1, -offset))
|
||||
{
|
||||
const auto corrected_offset = get_corrected_offset(
|
||||
offset, road, intersection[(index + 1) % intersection.size()]);
|
||||
// at the target intersection, we merge to the left, so we need to shift the current
|
||||
// angle to the right
|
||||
road.bearing = adjustAngle(road.bearing, -corrected_offset);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return intersection;
|
||||
}
|
||||
|
||||
|
||||
@@ -109,7 +109,8 @@ bool MergableRoadDetector::CanMergeRoad(const NodeID intersection_node,
|
||||
return true;
|
||||
|
||||
// finally check if two roads describe the direction
|
||||
return HaveSameDirection(intersection_node, lhs, rhs);
|
||||
return HaveSameDirection(intersection_node, lhs, rhs) &&
|
||||
!IsCircularShape(intersection_node, lhs, rhs);
|
||||
}
|
||||
|
||||
bool MergableRoadDetector::HaveIdenticalNames(const NameID lhs, const NameID rhs) const
|
||||
@@ -184,7 +185,8 @@ bool MergableRoadDetector::IsNarrowTriangle(const NodeID intersection_node,
|
||||
node_data_container.GetAnnotation(node_based_graph.GetEdgeData(lhs.eid).annotation_data)
|
||||
.name_id,
|
||||
lhs.bearing,
|
||||
/*requires entry=*/false);
|
||||
/*requires entry=*/false,
|
||||
false);
|
||||
|
||||
NodeBasedGraphWalker graph_walker(
|
||||
node_based_graph, node_data_container, intersection_generator);
|
||||
@@ -270,14 +272,10 @@ bool MergableRoadDetector::IsNarrowTriangle(const NodeID intersection_node,
|
||||
node_based_graph.GetTarget(right_accumulator.via_edge_id);
|
||||
}
|
||||
|
||||
bool MergableRoadDetector::HaveSameDirection(const NodeID intersection_node,
|
||||
const MergableRoadData &lhs,
|
||||
const MergableRoadData &rhs) const
|
||||
bool MergableRoadDetector::IsCircularShape(const NodeID intersection_node,
|
||||
const MergableRoadData &lhs,
|
||||
const MergableRoadData &rhs) const
|
||||
{
|
||||
if (angularDeviation(lhs.bearing, rhs.bearing) > MERGABLE_ANGLE_DIFFERENCE)
|
||||
return false;
|
||||
|
||||
// Find a coordinate following a road that is far away
|
||||
NodeBasedGraphWalker graph_walker(
|
||||
node_based_graph, node_data_container, intersection_generator);
|
||||
const auto getCoordinatesAlongWay = [&](const EdgeID edge_id, const double max_length) {
|
||||
@@ -286,7 +284,8 @@ bool MergableRoadDetector::HaveSameDirection(const NodeID intersection_node,
|
||||
node_data_container.GetAnnotation(node_based_graph.GetEdgeData(edge_id).annotation_data)
|
||||
.name_id,
|
||||
lhs.bearing,
|
||||
/*requires_entry=*/false);
|
||||
/*requires_entry=*/false,
|
||||
false);
|
||||
graph_walker.TraverseRoad(intersection_node, edge_id, accumulator, selector);
|
||||
|
||||
return std::make_pair(accumulator.accumulated_length, accumulator.coordinates);
|
||||
@@ -295,26 +294,12 @@ bool MergableRoadDetector::HaveSameDirection(const NodeID intersection_node,
|
||||
std::vector<util::Coordinate> coordinates_to_the_left, coordinates_to_the_right;
|
||||
double distance_traversed_to_the_left, distance_traversed_to_the_right;
|
||||
|
||||
// many roads only do short parallel segments. To get a good impression of how `parallel` two
|
||||
// roads are, we look 100 meters down the road (wich can be quite short for very broad roads).
|
||||
const double constexpr distance_to_extract = 150;
|
||||
|
||||
std::tie(distance_traversed_to_the_left, coordinates_to_the_left) =
|
||||
getCoordinatesAlongWay(lhs.eid, distance_to_extract);
|
||||
|
||||
// tuned parameter, if we didn't get as far as 40 meters, we might barely look past an
|
||||
// intersection.
|
||||
const auto constexpr MINIMUM_LENGTH_FOR_PARALLEL_DETECTION = 40;
|
||||
// quit early if the road is not very long
|
||||
if (distance_traversed_to_the_left <= MINIMUM_LENGTH_FOR_PARALLEL_DETECTION)
|
||||
return false;
|
||||
|
||||
std::tie(distance_traversed_to_the_right, coordinates_to_the_right) =
|
||||
getCoordinatesAlongWay(rhs.eid, distance_to_extract);
|
||||
|
||||
if (distance_traversed_to_the_right <= MINIMUM_LENGTH_FOR_PARALLEL_DETECTION)
|
||||
return false;
|
||||
|
||||
const auto connect_again = (coordinates_to_the_left.back() == coordinates_to_the_right.back());
|
||||
|
||||
// Tuning parameter to detect and don't merge roads close to circular shapes
|
||||
@@ -344,9 +329,55 @@ bool MergableRoadDetector::HaveSameDirection(const NodeID intersection_node,
|
||||
// then don't merge roads if A/L² is greater than the lower bound
|
||||
BOOST_ASSERT(area_to_squared_perimeter_ratio <= 1. / (4 * M_PI));
|
||||
if (area_to_squared_perimeter_ratio >= CIRCULAR_POLYGON_ISOPERIMETRIC_LOWER_BOUND)
|
||||
return false;
|
||||
return true;
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
bool MergableRoadDetector::HaveSameDirection(const NodeID intersection_node,
|
||||
const MergableRoadData &lhs,
|
||||
const MergableRoadData &rhs) const
|
||||
{
|
||||
if (angularDeviation(lhs.bearing, rhs.bearing) > MERGABLE_ANGLE_DIFFERENCE)
|
||||
return false;
|
||||
|
||||
// Find a coordinate following a road that is far away
|
||||
NodeBasedGraphWalker graph_walker(
|
||||
node_based_graph, node_data_container, intersection_generator);
|
||||
const auto getCoordinatesAlongWay = [&](const EdgeID edge_id, const double max_length) {
|
||||
LengthLimitedCoordinateAccumulator accumulator(coordinate_extractor, max_length);
|
||||
SelectStraightmostRoadByNameAndOnlyChoice selector(
|
||||
node_data_container.GetAnnotation(node_based_graph.GetEdgeData(edge_id).annotation_data)
|
||||
.name_id,
|
||||
lhs.bearing,
|
||||
/*requires_entry=*/false,
|
||||
true);
|
||||
graph_walker.TraverseRoad(intersection_node, edge_id, accumulator, selector);
|
||||
|
||||
return std::make_pair(accumulator.accumulated_length, accumulator.coordinates);
|
||||
};
|
||||
|
||||
std::vector<util::Coordinate> coordinates_to_the_left, coordinates_to_the_right;
|
||||
double distance_traversed_to_the_left, distance_traversed_to_the_right;
|
||||
|
||||
std::tie(distance_traversed_to_the_left, coordinates_to_the_left) =
|
||||
getCoordinatesAlongWay(lhs.eid, distance_to_extract);
|
||||
|
||||
// tuned parameter, if we didn't get as far as 40 meters, we might barely look past an
|
||||
// intersection.
|
||||
const auto constexpr MINIMUM_LENGTH_FOR_PARALLEL_DETECTION = 40;
|
||||
// quit early if the road is not very long
|
||||
if (distance_traversed_to_the_left <= MINIMUM_LENGTH_FOR_PARALLEL_DETECTION)
|
||||
return false;
|
||||
|
||||
std::tie(distance_traversed_to_the_right, coordinates_to_the_right) =
|
||||
getCoordinatesAlongWay(rhs.eid, distance_to_extract);
|
||||
|
||||
if (distance_traversed_to_the_right <= MINIMUM_LENGTH_FOR_PARALLEL_DETECTION)
|
||||
return false;
|
||||
|
||||
const auto connect_again = (coordinates_to_the_left.back() == coordinates_to_the_right.back());
|
||||
// sampling to correctly weight longer segments in regression calculations
|
||||
const auto constexpr SAMPLE_INTERVAL = 5;
|
||||
coordinates_to_the_left = coordinate_extractor.SampleCoordinates(
|
||||
@@ -395,6 +426,7 @@ bool MergableRoadDetector::HaveSameDirection(const NodeID intersection_node,
|
||||
|
||||
const auto combined_road_width = 0.5 * (lane_count_lhs + lane_count_rhs) * ASSUMED_LANE_WIDTH;
|
||||
const auto constexpr MAXIMAL_ALLOWED_SEPARATION_WIDTH = 8;
|
||||
|
||||
return distance_between_roads <= combined_road_width + MAXIMAL_ALLOWED_SEPARATION_WIDTH;
|
||||
}
|
||||
|
||||
|
||||
@@ -103,9 +103,12 @@ operator()(const NodeID /*nid*/,
|
||||
|
||||
// ---------------------------------------------------------------------------------
|
||||
SelectStraightmostRoadByNameAndOnlyChoice::SelectStraightmostRoadByNameAndOnlyChoice(
|
||||
const NameID desired_name_id, const double initial_bearing, const bool requires_entry)
|
||||
const NameID desired_name_id,
|
||||
const double initial_bearing,
|
||||
const bool requires_entry,
|
||||
const bool stop_on_ambiguous_turns)
|
||||
: desired_name_id(desired_name_id), initial_bearing(initial_bearing),
|
||||
requires_entry(requires_entry)
|
||||
requires_entry(requires_entry), stop_on_ambiguous_turns(stop_on_ambiguous_turns)
|
||||
{
|
||||
}
|
||||
|
||||
@@ -155,24 +158,79 @@ operator()(const NodeID /*nid*/,
|
||||
std::min_element(std::next(std::begin(intersection)), std::end(intersection), comparator);
|
||||
|
||||
const auto is_valid_choice = !requires_entry || min_element->entry_allowed;
|
||||
const auto is_only_choice_with_same_name =
|
||||
count_desired_name <= 2 && // <= in case we come from a bridge
|
||||
node_data_container
|
||||
.GetAnnotation(node_based_graph.GetEdgeData(min_element->eid).annotation_data)
|
||||
.name_id == desired_name_id &&
|
||||
angularDeviation(min_element->angle, STRAIGHT_ANGLE) < 100; // don't do crazy turns
|
||||
|
||||
if (!is_valid_choice)
|
||||
return {};
|
||||
|
||||
// only road exiting or continuing in the same general direction
|
||||
const auto has_valid_angle =
|
||||
((intersection.size() == 2 ||
|
||||
intersection.findClosestTurn(STRAIGHT_ANGLE) == min_element) &&
|
||||
angularDeviation(min_element->angle, STRAIGHT_ANGLE) < NARROW_TURN_ANGLE) &&
|
||||
angularDeviation(initial_bearing, min_element->bearing) < NARROW_TURN_ANGLE;
|
||||
|
||||
// in cases where we have two edges between roads, we can have quite severe angles due to the
|
||||
// random split OSRM does to break up parallel edges at any coordinate
|
||||
if (!is_valid_choice || !(is_only_choice_with_same_name || has_valid_angle))
|
||||
return {};
|
||||
else
|
||||
if (has_valid_angle)
|
||||
return (*min_element).eid;
|
||||
|
||||
// in some cases, stronger turns are appropriate. We allow turns of just a bit over 90 degrees,
|
||||
// if it's not a end of road situation. These angles come into play where roads split into dual
|
||||
// carriage-ways.
|
||||
//
|
||||
// e - - f
|
||||
// a - - - - b
|
||||
// c - - d
|
||||
// |
|
||||
// g
|
||||
//
|
||||
// is technically
|
||||
//
|
||||
//
|
||||
// a - - - - b (ce) - - (fg)
|
||||
// |
|
||||
// g
|
||||
const auto is_only_choice_with_same_name =
|
||||
count_desired_name <= 2 && // <= in case we come from a bridge, otherwise we have a u-turn
|
||||
// and the outgoing edge
|
||||
node_data_container
|
||||
.GetAnnotation(node_based_graph.GetEdgeData(min_element->eid).annotation_data)
|
||||
.name_id == desired_name_id &&
|
||||
angularDeviation(min_element->angle, STRAIGHT_ANGLE) < 100; // don't do crazy turns
|
||||
|
||||
// do not allow major turns in the road, if other similar turns are present
|
||||
// e.g.a turn at the end of the road:
|
||||
//
|
||||
// a - - a - - a - b - b
|
||||
// |
|
||||
// a - - a
|
||||
// |
|
||||
// c
|
||||
//
|
||||
// Such a turn can never be part of a merge
|
||||
// We check if there is a similar turn to the other side. If such a turn exists, we consider the
|
||||
// continuation of the road not possible
|
||||
if (stop_on_ambiguous_turns &&
|
||||
util::angularDeviation(STRAIGHT_ANGLE, min_element->angle) > GROUP_ANGLE)
|
||||
{
|
||||
auto opposite = intersection.findClosestTurn(util::bearing::reverse(min_element->angle));
|
||||
auto opposite_deviation = util::angularDeviation(min_element->angle, opposite->angle);
|
||||
// d - - - - c - - - -e
|
||||
// |
|
||||
// |
|
||||
// a - - - - b
|
||||
// from b-c onto min_element d with opposite side e
|
||||
if (opposite_deviation > (180 - FUZZY_ANGLE_DIFFERENCE))
|
||||
return {};
|
||||
|
||||
// e
|
||||
// |
|
||||
// a - - - - b - - - - -d
|
||||
// doing a left turn while straight is a choice
|
||||
auto const best = intersection.findClosestTurn(STRAIGHT_ANGLE);
|
||||
if (util::angularDeviation(best->angle, STRAIGHT_ANGLE) < FUZZY_ANGLE_DIFFERENCE)
|
||||
return {};
|
||||
}
|
||||
|
||||
return is_only_choice_with_same_name ? boost::optional<EdgeID>(min_element->eid) : boost::none;
|
||||
}
|
||||
|
||||
// ---------------------------------------------------------------------------------
|
||||
|
||||
@@ -34,7 +34,8 @@ bool SuppressModeHandler::canProcess(const NodeID,
|
||||
using std::end;
|
||||
|
||||
// travel modes for which navigation should be suppressed
|
||||
static const constexpr char suppressed[] = {TRAVEL_MODE_TRAIN, TRAVEL_MODE_FERRY};
|
||||
static const constexpr char suppressed[] = {extractor::TRAVEL_MODE_TRAIN,
|
||||
extractor::TRAVEL_MODE_FERRY};
|
||||
|
||||
// If the approach way is not on the suppression blacklist, and not all the exit ways share that
|
||||
// mode, there are no ways to suppress by this criteria.
|
||||
|
||||
@@ -78,7 +78,13 @@ TurnAnalysis::TurnAnalysis(const util::NodeBasedDynamicGraph &node_based_graph,
|
||||
node_data_container,
|
||||
coordinates,
|
||||
name_table,
|
||||
street_name_suffix_table)
|
||||
street_name_suffix_table),
|
||||
statistics_handler(intersection_generator,
|
||||
node_based_graph,
|
||||
node_data_container,
|
||||
coordinates,
|
||||
name_table,
|
||||
street_name_suffix_table)
|
||||
{
|
||||
}
|
||||
|
||||
@@ -175,6 +181,13 @@ Intersection TurnAnalysis::AssignTurnTypes(const NodeID node_prior_to_intersecti
|
||||
road.instruction.type = TurnType::OffRamp;
|
||||
});
|
||||
}
|
||||
|
||||
// After we ran all handlers and determined instruction type
|
||||
// and direction modifier gather statistics about our decisions.
|
||||
if (statistics_handler.canProcess(node_prior_to_intersection, entering_via_edge, intersection))
|
||||
intersection = statistics_handler(
|
||||
node_prior_to_intersection, entering_via_edge, std::move(intersection));
|
||||
|
||||
return intersection;
|
||||
}
|
||||
|
||||
|
||||
@@ -4,9 +4,12 @@
|
||||
#include "util/graph_loader.hpp"
|
||||
|
||||
#include "util/log.hpp"
|
||||
#include "util/timing_util.hpp"
|
||||
|
||||
#include <boost/assert.hpp>
|
||||
|
||||
#include <set>
|
||||
|
||||
namespace osrm
|
||||
{
|
||||
namespace extractor
|
||||
@@ -139,9 +142,38 @@ void NodeBasedGraphFactory::CompressGeometry()
|
||||
|
||||
void NodeBasedGraphFactory::CompressAnnotationData()
|
||||
{
|
||||
const constexpr AnnotationID INVALID_ANNOTATIONID = -1;
|
||||
// remap all entries to find which are used
|
||||
std::vector<AnnotationID> annotation_mapping(annotation_data.size(), INVALID_ANNOTATIONID);
|
||||
TIMER_START(compress_annotation);
|
||||
/** Main idea, that we need to remove duplicated and unreferenced data
|
||||
* For that:
|
||||
* 1. We create set, that contains indecies of unique data items. Just create
|
||||
* comparator, that compare data from annotation_data vector by passed index.
|
||||
* 2. Create cached id's unordered_map, where key - stored id in set,
|
||||
* value - index of item in a set from begin. We need that map, because
|
||||
* std::distance(set.begin(), it) is too slow O(N). So any words in that step we reorder
|
||||
* annotation data to the order it stored in a set. Apply new id's to edge data.
|
||||
* 3. Remove unused anootation_data items.
|
||||
* 4. At final step just need to sort result annotation_data in the same order as set.
|
||||
* That makes id's stored in edge data valid.
|
||||
*/
|
||||
struct IndexComparator
|
||||
{
|
||||
IndexComparator(const std::vector<NodeBasedEdgeAnnotation> &annotation_data_)
|
||||
: annotation_data(annotation_data_)
|
||||
{
|
||||
}
|
||||
|
||||
bool operator()(AnnotationID a, AnnotationID b) const
|
||||
{
|
||||
return annotation_data[a] < annotation_data[b];
|
||||
}
|
||||
|
||||
private:
|
||||
const std::vector<NodeBasedEdgeAnnotation> &annotation_data;
|
||||
};
|
||||
|
||||
/** 1 */
|
||||
IndexComparator comparator(annotation_data);
|
||||
std::set<AnnotationID, IndexComparator> unique_annotations(comparator);
|
||||
|
||||
// first we mark entries, by setting their mapping to 0
|
||||
for (const auto nbg_node_u : util::irange(0u, compressed_output_graph.GetNumberOfNodes()))
|
||||
@@ -150,22 +182,17 @@ void NodeBasedGraphFactory::CompressAnnotationData()
|
||||
for (EdgeID nbg_edge_id : compressed_output_graph.GetAdjacentEdgeRange(nbg_node_u))
|
||||
{
|
||||
auto const &edge = compressed_output_graph.GetEdgeData(nbg_edge_id);
|
||||
annotation_mapping[edge.annotation_data] = 0;
|
||||
unique_annotations.insert(edge.annotation_data);
|
||||
}
|
||||
}
|
||||
|
||||
// now compute a prefix sum on all entries that are 0 to find the new mapping
|
||||
AnnotationID prefix_sum = 0;
|
||||
for (std::size_t i = 0; i < annotation_mapping.size(); ++i)
|
||||
{
|
||||
if (annotation_mapping[i] == 0)
|
||||
annotation_mapping[i] = prefix_sum++;
|
||||
else
|
||||
{
|
||||
// flag for removal
|
||||
annotation_data[i].name_id = INVALID_NAMEID;
|
||||
}
|
||||
}
|
||||
// make additional map, because std::distance of std::set seems is O(N)
|
||||
// that very slow
|
||||
/** 2 */
|
||||
AnnotationID new_id = 0;
|
||||
std::unordered_map<AnnotationID, AnnotationID> cached_ids;
|
||||
for (auto id : unique_annotations)
|
||||
cached_ids[id] = new_id++;
|
||||
|
||||
// apply the mapping
|
||||
for (const auto nbg_node_u : util::irange(0u, compressed_output_graph.GetNumberOfNodes()))
|
||||
@@ -174,11 +201,24 @@ void NodeBasedGraphFactory::CompressAnnotationData()
|
||||
for (EdgeID nbg_edge_id : compressed_output_graph.GetAdjacentEdgeRange(nbg_node_u))
|
||||
{
|
||||
auto &edge = compressed_output_graph.GetEdgeData(nbg_edge_id);
|
||||
edge.annotation_data = annotation_mapping[edge.annotation_data];
|
||||
BOOST_ASSERT(edge.annotation_data != INVALID_ANNOTATIONID);
|
||||
auto const it = unique_annotations.find(edge.annotation_data);
|
||||
BOOST_ASSERT(it != unique_annotations.end());
|
||||
auto const it2 = cached_ids.find(*it);
|
||||
BOOST_ASSERT(it2 != cached_ids.end());
|
||||
|
||||
edge.annotation_data = it2->second;
|
||||
}
|
||||
}
|
||||
|
||||
/** 3 */
|
||||
// mark unused references for remove
|
||||
for (AnnotationID id = 0; id < annotation_data.size(); ++id)
|
||||
{
|
||||
auto const it = unique_annotations.find(id);
|
||||
if (it == unique_annotations.end() || *it != id)
|
||||
annotation_data[id].name_id = INVALID_NAMEID;
|
||||
}
|
||||
|
||||
// remove unreferenced entries, shifting other entries to the front
|
||||
const auto new_end =
|
||||
std::remove_if(annotation_data.begin(), annotation_data.end(), [&](auto const &data) {
|
||||
@@ -191,8 +231,15 @@ void NodeBasedGraphFactory::CompressAnnotationData()
|
||||
const auto old_size = annotation_data.size();
|
||||
// remove all remaining elements
|
||||
annotation_data.erase(new_end, annotation_data.end());
|
||||
util::Log() << " graoh compression removed " << (old_size - annotation_data.size())
|
||||
<< " annotations of " << old_size;
|
||||
|
||||
// reorder data in the same order
|
||||
/** 4 */
|
||||
std::sort(annotation_data.begin(), annotation_data.end());
|
||||
|
||||
TIMER_STOP(compress_annotation);
|
||||
util::Log() << " graph compression removed " << (old_size - annotation_data.size())
|
||||
<< " annotations of " << old_size << " in " << TIMER_SEC(compress_annotation)
|
||||
<< " seconds";
|
||||
}
|
||||
|
||||
void NodeBasedGraphFactory::ReleaseOsmNodes()
|
||||
|
||||
@@ -111,29 +111,29 @@ void Sol2ScriptingEnvironment::InitContext(LuaScriptingContext &context)
|
||||
|
||||
context.state.new_enum("mode",
|
||||
"inaccessible",
|
||||
TRAVEL_MODE_INACCESSIBLE,
|
||||
extractor::TRAVEL_MODE_INACCESSIBLE,
|
||||
"driving",
|
||||
TRAVEL_MODE_DRIVING,
|
||||
extractor::TRAVEL_MODE_DRIVING,
|
||||
"cycling",
|
||||
TRAVEL_MODE_CYCLING,
|
||||
extractor::TRAVEL_MODE_CYCLING,
|
||||
"walking",
|
||||
TRAVEL_MODE_WALKING,
|
||||
extractor::TRAVEL_MODE_WALKING,
|
||||
"ferry",
|
||||
TRAVEL_MODE_FERRY,
|
||||
extractor::TRAVEL_MODE_FERRY,
|
||||
"train",
|
||||
TRAVEL_MODE_TRAIN,
|
||||
extractor::TRAVEL_MODE_TRAIN,
|
||||
"pushing_bike",
|
||||
TRAVEL_MODE_PUSHING_BIKE,
|
||||
extractor::TRAVEL_MODE_PUSHING_BIKE,
|
||||
"steps_up",
|
||||
TRAVEL_MODE_STEPS_UP,
|
||||
extractor::TRAVEL_MODE_STEPS_UP,
|
||||
"steps_down",
|
||||
TRAVEL_MODE_STEPS_DOWN,
|
||||
extractor::TRAVEL_MODE_STEPS_DOWN,
|
||||
"river_up",
|
||||
TRAVEL_MODE_RIVER_UP,
|
||||
extractor::TRAVEL_MODE_RIVER_UP,
|
||||
"river_down",
|
||||
TRAVEL_MODE_RIVER_DOWN,
|
||||
extractor::TRAVEL_MODE_RIVER_DOWN,
|
||||
"route",
|
||||
TRAVEL_MODE_ROUTE);
|
||||
extractor::TRAVEL_MODE_ROUTE);
|
||||
|
||||
context.state.new_enum("road_priority_class",
|
||||
"motorway",
|
||||
@@ -159,80 +159,6 @@ void Sol2ScriptingEnvironment::InitContext(LuaScriptingContext &context)
|
||||
"connectivity",
|
||||
extractor::guidance::RoadPriorityClass::CONNECTIVITY);
|
||||
|
||||
context.state.new_enum("turn_type",
|
||||
"invalid",
|
||||
extractor::guidance::TurnType::Invalid,
|
||||
"new_name",
|
||||
extractor::guidance::TurnType::NewName,
|
||||
"continue",
|
||||
extractor::guidance::TurnType::Continue,
|
||||
"turn",
|
||||
extractor::guidance::TurnType::Turn,
|
||||
"merge",
|
||||
extractor::guidance::TurnType::Merge,
|
||||
"on_ramp",
|
||||
extractor::guidance::TurnType::OnRamp,
|
||||
"off_ramp",
|
||||
extractor::guidance::TurnType::OffRamp,
|
||||
"fork",
|
||||
extractor::guidance::TurnType::Fork,
|
||||
"end_of_road",
|
||||
extractor::guidance::TurnType::EndOfRoad,
|
||||
"notification",
|
||||
extractor::guidance::TurnType::Notification,
|
||||
"enter_roundabout",
|
||||
extractor::guidance::TurnType::EnterRoundabout,
|
||||
"enter_and_exit_roundabout",
|
||||
extractor::guidance::TurnType::EnterAndExitRoundabout,
|
||||
"enter_rotary",
|
||||
extractor::guidance::TurnType::EnterRotary,
|
||||
"enter_and_exit_rotary",
|
||||
extractor::guidance::TurnType::EnterAndExitRotary,
|
||||
"enter_roundabout_intersection",
|
||||
extractor::guidance::TurnType::EnterRoundaboutIntersection,
|
||||
"enter_and_exit_roundabout_intersection",
|
||||
extractor::guidance::TurnType::EnterAndExitRoundaboutIntersection,
|
||||
"use_lane",
|
||||
extractor::guidance::TurnType::Suppressed,
|
||||
"no_turn",
|
||||
extractor::guidance::TurnType::NoTurn,
|
||||
"suppressed",
|
||||
extractor::guidance::TurnType::Suppressed,
|
||||
"enter_roundabout_at_exit",
|
||||
extractor::guidance::TurnType::EnterRoundaboutAtExit,
|
||||
"exit_roundabout",
|
||||
extractor::guidance::TurnType::ExitRoundabout,
|
||||
"enter_rotary_at_exit",
|
||||
extractor::guidance::TurnType::EnterRotaryAtExit,
|
||||
"exit_rotary",
|
||||
extractor::guidance::TurnType::ExitRotary,
|
||||
"enter_roundabout_intersection_at_exit",
|
||||
extractor::guidance::TurnType::EnterRoundaboutIntersectionAtExit,
|
||||
"exit_roundabout_intersection",
|
||||
extractor::guidance::TurnType::ExitRoundaboutIntersection,
|
||||
"stay_on_roundabout",
|
||||
extractor::guidance::TurnType::StayOnRoundabout,
|
||||
"sliproad",
|
||||
extractor::guidance::TurnType::Sliproad);
|
||||
|
||||
context.state.new_enum("direction_modifier",
|
||||
"u_turn",
|
||||
extractor::guidance::DirectionModifier::UTurn,
|
||||
"sharp_right",
|
||||
extractor::guidance::DirectionModifier::SharpRight,
|
||||
"right",
|
||||
extractor::guidance::DirectionModifier::Right,
|
||||
"slight_right",
|
||||
extractor::guidance::DirectionModifier::SlightRight,
|
||||
"straight",
|
||||
extractor::guidance::DirectionModifier::Straight,
|
||||
"slight_left",
|
||||
extractor::guidance::DirectionModifier::SlightLeft,
|
||||
"left",
|
||||
extractor::guidance::DirectionModifier::Left,
|
||||
"sharp_left",
|
||||
extractor::guidance::DirectionModifier::SharpLeft);
|
||||
|
||||
context.state.new_enum("item_type",
|
||||
"node",
|
||||
osmium::item_type::node,
|
||||
@@ -369,8 +295,16 @@ void Sol2ScriptingEnvironment::InitContext(LuaScriptingContext &context)
|
||||
&ExtractionWay::backward_rate,
|
||||
"name",
|
||||
sol::property(&ExtractionWay::GetName, &ExtractionWay::SetName),
|
||||
"ref",
|
||||
sol::property(&ExtractionWay::GetRef, &ExtractionWay::SetRef),
|
||||
"ref", // backward compatibility
|
||||
sol::property(&ExtractionWay::GetForwardRef,
|
||||
[](ExtractionWay &way, const char *ref) {
|
||||
way.SetForwardRef(ref);
|
||||
way.SetBackwardRef(ref);
|
||||
}),
|
||||
"forward_ref",
|
||||
sol::property(&ExtractionWay::GetForwardRef, &ExtractionWay::SetForwardRef),
|
||||
"backward_ref",
|
||||
sol::property(&ExtractionWay::GetBackwardRef, &ExtractionWay::SetBackwardRef),
|
||||
"pronunciation",
|
||||
sol::property(&ExtractionWay::GetPronunciation, &ExtractionWay::SetPronunciation),
|
||||
"destinations",
|
||||
@@ -479,26 +413,6 @@ void Sol2ScriptingEnvironment::InitContext(LuaScriptingContext &context)
|
||||
"duration",
|
||||
&ExtractionSegment::duration);
|
||||
|
||||
context.state.new_usertype<ExtractionTurn>("ExtractionTurn",
|
||||
"angle",
|
||||
&ExtractionTurn::angle,
|
||||
"turn_type",
|
||||
&ExtractionTurn::turn_type,
|
||||
"direction_modifier",
|
||||
&ExtractionTurn::direction_modifier,
|
||||
"has_traffic_light",
|
||||
&ExtractionTurn::has_traffic_light,
|
||||
"weight",
|
||||
&ExtractionTurn::weight,
|
||||
"duration",
|
||||
&ExtractionTurn::duration,
|
||||
"source_restricted",
|
||||
&ExtractionTurn::source_restricted,
|
||||
"target_restricted",
|
||||
&ExtractionTurn::target_restricted,
|
||||
"is_left_hand_driving",
|
||||
&ExtractionTurn::is_left_hand_driving);
|
||||
|
||||
// Keep in mind .location is available only if .pbf is preprocessed to set the location with the
|
||||
// ref using osmium command "osmium add-locations-to-ways"
|
||||
context.state.new_usertype<osmium::NodeRef>(
|
||||
@@ -645,16 +559,156 @@ void Sol2ScriptingEnvironment::InitContext(LuaScriptingContext &context)
|
||||
}
|
||||
};
|
||||
|
||||
auto initialize_V3_extraction_turn = [&]() {
|
||||
|
||||
context.state.new_usertype<ExtractionTurn>(
|
||||
"ExtractionTurn",
|
||||
"angle",
|
||||
&ExtractionTurn::angle,
|
||||
"turn_type",
|
||||
sol::property([](const ExtractionTurn &turn) {
|
||||
if (turn.number_of_roads > 2 || turn.source_mode != turn.target_mode ||
|
||||
turn.is_u_turn)
|
||||
return guidance::TurnType::Turn;
|
||||
else
|
||||
return guidance::TurnType::NoTurn;
|
||||
}),
|
||||
"direction_modifier",
|
||||
sol::property([](const ExtractionTurn &turn) {
|
||||
if (turn.is_u_turn)
|
||||
return guidance::DirectionModifier::UTurn;
|
||||
else
|
||||
return guidance::DirectionModifier::Straight;
|
||||
}),
|
||||
"has_traffic_light",
|
||||
&ExtractionTurn::has_traffic_light,
|
||||
"weight",
|
||||
&ExtractionTurn::weight,
|
||||
"duration",
|
||||
&ExtractionTurn::duration,
|
||||
"source_restricted",
|
||||
&ExtractionTurn::source_restricted,
|
||||
"target_restricted",
|
||||
&ExtractionTurn::target_restricted,
|
||||
"is_left_hand_driving",
|
||||
&ExtractionTurn::is_left_hand_driving);
|
||||
|
||||
context.state.new_enum("turn_type",
|
||||
"invalid",
|
||||
extractor::guidance::TurnType::Invalid,
|
||||
"new_name",
|
||||
extractor::guidance::TurnType::NewName,
|
||||
"continue",
|
||||
extractor::guidance::TurnType::Continue,
|
||||
"turn",
|
||||
extractor::guidance::TurnType::Turn,
|
||||
"merge",
|
||||
extractor::guidance::TurnType::Merge,
|
||||
"on_ramp",
|
||||
extractor::guidance::TurnType::OnRamp,
|
||||
"off_ramp",
|
||||
extractor::guidance::TurnType::OffRamp,
|
||||
"fork",
|
||||
extractor::guidance::TurnType::Fork,
|
||||
"end_of_road",
|
||||
extractor::guidance::TurnType::EndOfRoad,
|
||||
"notification",
|
||||
extractor::guidance::TurnType::Notification,
|
||||
"enter_roundabout",
|
||||
extractor::guidance::TurnType::EnterRoundabout,
|
||||
"enter_and_exit_roundabout",
|
||||
extractor::guidance::TurnType::EnterAndExitRoundabout,
|
||||
"enter_rotary",
|
||||
extractor::guidance::TurnType::EnterRotary,
|
||||
"enter_and_exit_rotary",
|
||||
extractor::guidance::TurnType::EnterAndExitRotary,
|
||||
"enter_roundabout_intersection",
|
||||
extractor::guidance::TurnType::EnterRoundaboutIntersection,
|
||||
"enter_and_exit_roundabout_intersection",
|
||||
extractor::guidance::TurnType::EnterAndExitRoundaboutIntersection,
|
||||
"use_lane",
|
||||
extractor::guidance::TurnType::Suppressed,
|
||||
"no_turn",
|
||||
extractor::guidance::TurnType::NoTurn,
|
||||
"suppressed",
|
||||
extractor::guidance::TurnType::Suppressed,
|
||||
"enter_roundabout_at_exit",
|
||||
extractor::guidance::TurnType::EnterRoundaboutAtExit,
|
||||
"exit_roundabout",
|
||||
extractor::guidance::TurnType::ExitRoundabout,
|
||||
"enter_rotary_at_exit",
|
||||
extractor::guidance::TurnType::EnterRotaryAtExit,
|
||||
"exit_rotary",
|
||||
extractor::guidance::TurnType::ExitRotary,
|
||||
"enter_roundabout_intersection_at_exit",
|
||||
extractor::guidance::TurnType::EnterRoundaboutIntersectionAtExit,
|
||||
"exit_roundabout_intersection",
|
||||
extractor::guidance::TurnType::ExitRoundaboutIntersection,
|
||||
"stay_on_roundabout",
|
||||
extractor::guidance::TurnType::StayOnRoundabout,
|
||||
"sliproad",
|
||||
extractor::guidance::TurnType::Sliproad);
|
||||
|
||||
context.state.new_enum("direction_modifier",
|
||||
"u_turn",
|
||||
extractor::guidance::DirectionModifier::UTurn,
|
||||
"sharp_right",
|
||||
extractor::guidance::DirectionModifier::SharpRight,
|
||||
"right",
|
||||
extractor::guidance::DirectionModifier::Right,
|
||||
"slight_right",
|
||||
extractor::guidance::DirectionModifier::SlightRight,
|
||||
"straight",
|
||||
extractor::guidance::DirectionModifier::Straight,
|
||||
"slight_left",
|
||||
extractor::guidance::DirectionModifier::SlightLeft,
|
||||
"left",
|
||||
extractor::guidance::DirectionModifier::Left,
|
||||
"sharp_left",
|
||||
extractor::guidance::DirectionModifier::SharpLeft);
|
||||
};
|
||||
|
||||
switch (context.api_version)
|
||||
{
|
||||
case 4:
|
||||
{
|
||||
context.state.new_usertype<ExtractionTurn>("ExtractionTurn",
|
||||
"angle",
|
||||
&ExtractionTurn::angle,
|
||||
"number_of_roads",
|
||||
&ExtractionTurn::number_of_roads,
|
||||
"is_u_turn",
|
||||
&ExtractionTurn::is_u_turn,
|
||||
"has_traffic_light",
|
||||
&ExtractionTurn::has_traffic_light,
|
||||
"weight",
|
||||
&ExtractionTurn::weight,
|
||||
"duration",
|
||||
&ExtractionTurn::duration,
|
||||
"source_restricted",
|
||||
&ExtractionTurn::source_restricted,
|
||||
"target_restricted",
|
||||
&ExtractionTurn::target_restricted,
|
||||
"is_left_hand_driving",
|
||||
&ExtractionTurn::is_left_hand_driving,
|
||||
"source_mode",
|
||||
&ExtractionTurn::source_mode,
|
||||
"target_mode",
|
||||
&ExtractionTurn::target_mode);
|
||||
initV2Context();
|
||||
break;
|
||||
}
|
||||
case 3:
|
||||
case 2:
|
||||
{
|
||||
initialize_V3_extraction_turn();
|
||||
initV2Context();
|
||||
break;
|
||||
}
|
||||
case 1:
|
||||
{
|
||||
initialize_V3_extraction_turn();
|
||||
|
||||
// cache references to functions for faster execution
|
||||
context.turn_function = context.state["turn_function"];
|
||||
context.node_function = context.state["node_function"];
|
||||
@@ -685,6 +739,8 @@ void Sol2ScriptingEnvironment::InitContext(LuaScriptingContext &context)
|
||||
break;
|
||||
}
|
||||
case 0:
|
||||
initialize_V3_extraction_turn();
|
||||
|
||||
// cache references to functions for faster execution
|
||||
context.turn_function = context.state["turn_function"];
|
||||
context.node_function = context.state["node_function"];
|
||||
@@ -843,6 +899,7 @@ std::vector<std::vector<std::string>> Sol2ScriptingEnvironment::GetExcludableCla
|
||||
auto &context = GetSol2Context();
|
||||
switch (context.api_version)
|
||||
{
|
||||
case 4:
|
||||
case 3:
|
||||
case 2:
|
||||
return Sol2ScriptingEnvironment::GetStringListsFromTable("excludable");
|
||||
@@ -856,6 +913,7 @@ std::vector<std::string> Sol2ScriptingEnvironment::GetClassNames()
|
||||
auto &context = GetSol2Context();
|
||||
switch (context.api_version)
|
||||
{
|
||||
case 4:
|
||||
case 3:
|
||||
case 2:
|
||||
return Sol2ScriptingEnvironment::GetStringListFromTable("classes");
|
||||
@@ -869,6 +927,7 @@ std::vector<std::string> Sol2ScriptingEnvironment::GetNameSuffixList()
|
||||
auto &context = GetSol2Context();
|
||||
switch (context.api_version)
|
||||
{
|
||||
case 4:
|
||||
case 3:
|
||||
case 2:
|
||||
return Sol2ScriptingEnvironment::GetStringListFromTable("suffix_list");
|
||||
@@ -884,6 +943,7 @@ std::vector<std::string> Sol2ScriptingEnvironment::GetRestrictions()
|
||||
auto &context = GetSol2Context();
|
||||
switch (context.api_version)
|
||||
{
|
||||
case 4:
|
||||
case 3:
|
||||
case 2:
|
||||
return Sol2ScriptingEnvironment::GetStringListFromTable("restrictions");
|
||||
@@ -899,6 +959,7 @@ std::vector<std::string> Sol2ScriptingEnvironment::GetRelations()
|
||||
auto &context = GetSol2Context();
|
||||
switch (context.api_version)
|
||||
{
|
||||
case 4:
|
||||
case 3:
|
||||
return Sol2ScriptingEnvironment::GetStringListFromTable("relation_types");
|
||||
default:
|
||||
@@ -912,6 +973,7 @@ void Sol2ScriptingEnvironment::ProcessTurn(ExtractionTurn &turn)
|
||||
|
||||
switch (context.api_version)
|
||||
{
|
||||
case 4:
|
||||
case 3:
|
||||
case 2:
|
||||
if (context.has_turn_penalty_function)
|
||||
@@ -943,14 +1005,14 @@ void Sol2ScriptingEnvironment::ProcessTurn(ExtractionTurn &turn)
|
||||
case 0:
|
||||
if (context.has_turn_penalty_function)
|
||||
{
|
||||
if (turn.turn_type != guidance::TurnType::NoTurn)
|
||||
if (turn.number_of_roads > 2)
|
||||
{
|
||||
// Get turn duration and convert deci-seconds to seconds
|
||||
turn.duration = static_cast<double>(context.turn_function(turn.angle)) / 10.;
|
||||
BOOST_ASSERT(turn.weight == 0);
|
||||
|
||||
// add U-turn penalty
|
||||
if (turn.direction_modifier == guidance::DirectionModifier::UTurn)
|
||||
if (turn.is_u_turn)
|
||||
turn.duration += context.properties.GetUturnPenalty();
|
||||
}
|
||||
else
|
||||
@@ -979,6 +1041,7 @@ void Sol2ScriptingEnvironment::ProcessSegment(ExtractionSegment &segment)
|
||||
{
|
||||
switch (context.api_version)
|
||||
{
|
||||
case 4:
|
||||
case 3:
|
||||
case 2:
|
||||
context.segment_function(context.profile_table, segment);
|
||||
@@ -1003,6 +1066,7 @@ void LuaScriptingContext::ProcessNode(const osmium::Node &node,
|
||||
|
||||
switch (api_version)
|
||||
{
|
||||
case 4:
|
||||
case 3:
|
||||
node_function(profile_table, node, result, relations);
|
||||
break;
|
||||
@@ -1024,6 +1088,7 @@ void LuaScriptingContext::ProcessWay(const osmium::Way &way,
|
||||
|
||||
switch (api_version)
|
||||
{
|
||||
case 4:
|
||||
case 3:
|
||||
way_function(profile_table, way, result, relations);
|
||||
break;
|
||||
|
||||
@@ -61,7 +61,7 @@ return_code parseArguments(int argc,
|
||||
->composing(),
|
||||
"Lookup files containing from_, to_, via_nodes, and turn penalties to adjust turn weights")(
|
||||
"level-cache,o",
|
||||
boost::program_options::value<bool>(&contractor_config.use_cached_priority)
|
||||
boost::program_options::bool_switch(&contractor_config.use_cached_priority)
|
||||
->default_value(false),
|
||||
"DEPRECATED: Will always be false. Use .level file to retain the contraction level for "
|
||||
"each "
|
||||
|
||||
@@ -58,7 +58,7 @@ return_code parseArguments(int argc,
|
||||
->default_value(false),
|
||||
"Use metadata during osm parsing (This can affect the extraction performance).")(
|
||||
"parse-conditional-restrictions",
|
||||
boost::program_options::value<bool>(&extractor_config.parse_conditionals)
|
||||
boost::program_options::bool_switch(&extractor_config.parse_conditionals)
|
||||
->implicit_value(true)
|
||||
->default_value(false),
|
||||
"Save conditional restrictions found during extraction to disk for use "
|
||||
@@ -67,10 +67,10 @@ return_code parseArguments(int argc,
|
||||
&extractor_config.location_dependent_data_paths)
|
||||
->composing(),
|
||||
"GeoJSON files with location-dependent data")(
|
||||
"use-locations-cache",
|
||||
boost::program_options::value<bool>(&extractor_config.use_locations_cache)
|
||||
->implicit_value(true)
|
||||
->default_value(extractor_config.use_locations_cache),
|
||||
"disable-location-cache",
|
||||
boost::program_options::bool_switch(&extractor_config.use_locations_cache)
|
||||
->implicit_value(false)
|
||||
->default_value(true),
|
||||
"Use internal nodes locations cache for location-dependent data lookups");
|
||||
|
||||
bool dummy;
|
||||
@@ -82,7 +82,7 @@ return_code parseArguments(int argc,
|
||||
boost::program_options::value<boost::filesystem::path>(&extractor_config.input_path),
|
||||
"Input file in .osm, .osm.bz2 or .osm.pbf format")(
|
||||
"generate-edge-lookup",
|
||||
boost::program_options::value<bool>(&dummy)->implicit_value(true)->default_value(false),
|
||||
boost::program_options::bool_switch(&dummy)->implicit_value(true)->default_value(false),
|
||||
"Not used anymore");
|
||||
|
||||
// positional option
|
||||
|
||||
@@ -10,7 +10,7 @@ exports.three_test_coordinates = [[7.41337, 43.72956],
|
||||
|
||||
exports.two_test_coordinates = exports.three_test_coordinates.slice(0, 2)
|
||||
|
||||
exports.test_tile = {'at': [17059, 11948, 15], 'size': 167166};
|
||||
exports.test_tile = {'at': [17059, 11948, 15], 'size': 168606};
|
||||
|
||||
|
||||
// Test files generated by the routing engine; check test/data
|
||||
|
||||
@@ -1,3 +1,5 @@
|
||||
#include "extractor/travel_mode.hpp"
|
||||
|
||||
#include "engine/guidance/assemble_geometry.hpp"
|
||||
#include "engine/guidance/assemble_leg.hpp"
|
||||
#include "engine/guidance/assemble_overview.hpp"
|
||||
@@ -12,6 +14,7 @@ BOOST_AUTO_TEST_SUITE(guidance_assembly)
|
||||
|
||||
BOOST_AUTO_TEST_CASE(trim_short_segments)
|
||||
{
|
||||
using namespace osrm::extractor;
|
||||
using namespace osrm::extractor::guidance;
|
||||
using namespace osrm::engine::guidance;
|
||||
using namespace osrm::engine;
|
||||
@@ -36,6 +39,7 @@ BOOST_AUTO_TEST_CASE(trim_short_segments)
|
||||
|
||||
// Check that duplicated coordinate in the end is removed
|
||||
std::vector<RouteStep> steps = {{324,
|
||||
false,
|
||||
"Central Park West",
|
||||
"",
|
||||
"",
|
||||
@@ -57,6 +61,7 @@ BOOST_AUTO_TEST_CASE(trim_short_segments)
|
||||
3,
|
||||
{intersection1}},
|
||||
{324,
|
||||
false,
|
||||
"Central Park West",
|
||||
"",
|
||||
"",
|
||||
|
||||
@@ -1,4 +1,5 @@
|
||||
#include "engine/api/json_factory.hpp"
|
||||
#include "extractor/guidance/turn_instruction.hpp"
|
||||
|
||||
#include <boost/test/test_case_template.hpp>
|
||||
#include <boost/test/unit_test.hpp>
|
||||
|
||||
@@ -216,7 +216,7 @@ class ContiguousInternalMemoryDataFacade<routing_algorithms::offline::Algorithm>
|
||||
|
||||
extractor::TravelMode GetTravelMode(const NodeID /*id*/) const override
|
||||
{
|
||||
return TRAVEL_MODE_DRIVING;
|
||||
return extractor::TRAVEL_MODE_DRIVING;
|
||||
}
|
||||
|
||||
std::vector<RTreeLeaf> GetEdgesInBox(const util::Coordinate /*south_west*/,
|
||||
@@ -366,6 +366,7 @@ class ContiguousInternalMemoryDataFacade<routing_algorithms::offline::Algorithm>
|
||||
|
||||
util::guidance::EntryClass GetEntryClass(const EdgeID /*turn_id*/) const override { return {}; }
|
||||
bool IsLeftHandDriving(const NodeID /*id*/) const override { return false; }
|
||||
bool IsSegregated(const NodeID /*id*/) const override { return false; }
|
||||
};
|
||||
|
||||
} // datafacade
|
||||
|
||||
@@ -105,6 +105,11 @@ BOOST_AUTO_TEST_CASE(test_nearest_response_for_location_in_small_component)
|
||||
// Nearest service should snap to road network without considering components.
|
||||
const auto distance = waypoint_object.values.at("distance").get<json::Number>().value;
|
||||
BOOST_CHECK_LT(distance, 20);
|
||||
|
||||
const auto &nodes = waypoint_object.values.at("nodes").get<json::Array>().values;
|
||||
BOOST_CHECK(nodes.size() == 2);
|
||||
BOOST_CHECK(nodes[0].get<util::json::Number>().value != 0);
|
||||
BOOST_CHECK(nodes[1].get<util::json::Number>().value != 0);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -64,6 +64,7 @@ BOOST_AUTO_TEST_CASE(test_route_same_coordinates_fixture)
|
||||
{"geometry", "yw_jGupkl@??"},
|
||||
{"name", "Boulevard du Larvotto"},
|
||||
{"mode", "driving"},
|
||||
{"driving_side", "right"},
|
||||
{"maneuver",
|
||||
json::Object{{
|
||||
{"location", location},
|
||||
@@ -84,6 +85,7 @@ BOOST_AUTO_TEST_CASE(test_route_same_coordinates_fixture)
|
||||
{"geometry", "yw_jGupkl@"},
|
||||
{"name", "Boulevard du Larvotto"},
|
||||
{"mode", "driving"},
|
||||
{"driving_side", "right"},
|
||||
{"maneuver",
|
||||
json::Object{{{"location", location},
|
||||
{"bearing_before", 58},
|
||||
|
||||
@@ -199,7 +199,7 @@ class MockBaseDataFacade : public engine::datafacade::BaseDataFacade
|
||||
|
||||
extractor::TravelMode GetTravelMode(const NodeID /* id */) const override
|
||||
{
|
||||
return TRAVEL_MODE_INACCESSIBLE;
|
||||
return extractor::TRAVEL_MODE_INACCESSIBLE;
|
||||
}
|
||||
|
||||
extractor::ClassData GetClassData(const NodeID /*id*/) const override final { return 0; }
|
||||
@@ -224,6 +224,7 @@ class MockBaseDataFacade : public engine::datafacade::BaseDataFacade
|
||||
unsigned GetWeightPrecision() const override final { return 1; }
|
||||
double GetWeightMultiplier() const override final { return 10.; }
|
||||
bool IsLeftHandDriving(const NodeID /*id*/) const override { return false; }
|
||||
bool IsSegregated(const NodeID /*id*/) const override { return false; }
|
||||
|
||||
util::guidance::TurnBearing PreTurnBearing(const EdgeID /*eid*/) const override final
|
||||
{
|
||||
|
||||
Reference in New Issue
Block a user