Compare commits

...

62 Commits

Author SHA1 Message Date
Daniel Patterson c8c3a49fb5 Set changelog to 5.14 2017-11-22 12:36:01 -08:00
Daniel Patterson 3ae313d35d Make 5.14.0-rc.1 2017-11-22 12:35:30 -08:00
Daniel Patterson 9fca6987c9 Update CHANGELOG for 5.14 release prep 2017-11-22 12:34:03 -08:00
Michael Krasnyk 7361558c19 Allow single edge paths in MLD alternatives, #4691 2017-11-21 12:28:44 +01:00
karenzshea 834890cf0b construct extract/contract configs to disable conditional restriction parsing by default 2017-11-20 16:55:17 +00:00
vng a53794f864 Code review fixes. 2017-11-16 15:08:30 +01:00
vng 8fa98ed27d Increase max segregated distances. 2017-11-16 15:08:30 +01:00
vng 111030864c Use segregated flag as a bit in EdgeBasedNode. 2017-11-16 15:08:30 +01:00
vng 90e361c3dc Use immutable node-based-graph for segregated edges. 2017-11-16 15:08:30 +01:00
vng 32e6ccb037 Code review fixes. 2017-11-16 15:08:30 +01:00
vng 258fcd8626 Fixed test tile test according to new algorithm output. 2017-11-16 15:08:30 +01:00
vng 92c4a228e1 Revert suppressSegregated routing. 2017-11-16 15:08:30 +01:00
vng 9eae1de9bc Fixes for segregated length threshold. 2017-11-16 15:08:30 +01:00
vng 76f793533a Use copressed node-based graph for segregated edges check. 2017-11-16 15:08:30 +01:00
vng ec7e58e10e Pass edge-based node segregated flag to the post processing routine. 2017-11-16 15:08:30 +01:00
vng ac5e095d17 Store and pass segregated flag to the data facade. 2017-11-16 15:08:30 +01:00
vng ee7912f882 Calculating segregated node-based edges. 2017-11-16 15:08:30 +01:00
Denis Koronchik f460a9f17e Add code to draw segregated nodes in a tile layer 2017-11-16 15:08:30 +01:00
vng 37685dae73 Added segregated test #4273. 2017-11-16 15:08:30 +01:00
Daniel Patterson 5b58445535 Expose driving_side as a property on RouteStep 2017-11-09 10:08:11 -05:00
Michael Krasnyk 5b79640b44 Don't compute new modifier for merge instructions in collapsing 2017-11-08 11:26:47 -05:00
Michael Krasnyk 921471a153 Test of merging onto a motorway with junction references 2017-11-08 11:26:47 -05:00
Daniel J. Hofmann 3a1bf2c85d Slightly decreases roundabout turn radius from 25m to 15m 2017-11-07 13:45:57 -05:00
Daniel J. Hofmann 9b83649a03 Fixes AppVeyor tests 2017-11-06 14:38:21 -05:00
Daniel J. Hofmann 2224389fb3 Filters zero value histograms, formats numbers 2017-11-06 14:38:21 -05:00
Daniel J. Hofmann aed7bd852d Prints turn types and modifiers as strings 2017-11-06 14:38:21 -05:00
Daniel J. Hofmann c5b48e3506 Adds a statistics handler for turn types and modifiers 2017-11-06 14:38:21 -05:00
Kajari Ghosh 73f4e1d45a update changelog 2017-11-06 13:34:02 -05:00
Kajari Ghosh 002da129c8 update tests 2017-11-06 13:34:02 -05:00
Kajari Ghosh 1b545fee8a update lua profile to use new process_turn 2017-11-06 13:34:02 -05:00
Kajari Ghosh cbc96ec492 refactor ExtractionTurn and ProcessTurn c++ code 2017-11-06 13:34:02 -05:00
Daniel J. Hofmann c95d845876 Adds Node 8 jobs to Travis, resolves #4657 2017-11-02 20:17:17 +00:00
Daniel Patterson ac7705e9a0 Ensure .pc installation to the same heirarchy as the actual libraries (usually /usr/local/lib) 2017-11-01 19:40:31 +00:00
Patrick Niklaus 0b6eb85106 Fix formating 2017-11-01 14:25:07 +00:00
Moritz Kobitzsch e197dae54d do not consider empty-names + empty-refs a valid name for u-turns 2017-11-01 14:25:07 +00:00
Moritz Kobitzsch 4bf3c97476 add test-case illustrating misuse of names in collapse 2017-11-01 14:25:07 +00:00
Daniel Patterson 19d2e82d15 Reduce docker image size to about 20MB by using a multistage build. 2017-10-31 23:35:01 -04:00
Michael Krasnyk eb48945807 Add use of LUA_LIBRARY_DIRS, #4646 2017-10-31 23:35:01 -04:00
Patrick Niklaus a68db86dc8 [skip ci] Bump OSRM version to 5.14 2017-10-31 16:17:07 +00:00
Daniel J. H 948025440f Clarifies docs for roundabout exits (#4640) 2017-10-26 14:44:06 -07:00
Daniel J. Hofmann 8365e20d4f Adds cardinal_directions flag to profiles and disables ref-rewriting by default 2017-10-26 20:38:41 +01:00
Denis Koronchik 0fc6903d7e Fix issue #4585 2017-10-25 14:11:33 +02:00
Moritz Kobitzsch 23fd27422b normalise angles only if an improvement 2017-10-25 10:17:14 +02:00
Moritz Kobitzsch e965cf12f8 add testcase illustrating changes to angle adjustments 2017-10-25 10:17:14 +02:00
Michael Krasnyk 523be8f7e5 Add unclassified roads to restricted_highway_whitelist, #4631 2017-10-24 09:59:07 +02:00
Patrick Niklaus c2a605a70d Contract the exclude-flag sub-graphs as well 2017-10-24 09:46:44 +02:00
Moritz Kobitzsch 910ee0829f make circular detection covered again 2017-10-23 09:06:59 +02:00
Moritz Kobitzsch 704cf314d4 explicitly check for 90 degree turns / turning onto segregated roads 2017-10-23 09:06:59 +02:00
Moritz Kobitzsch b8651bfac9 do not merge segregated highways in if there is actual turns involved 2017-10-23 09:06:59 +02:00
Moritz Kobitzsch bf28e40ba6 add further tests for segregated roads 2017-10-23 09:06:59 +02:00
Patrick Niklaus a8de007d98 Rename locations-cache -> location-cache 2017-10-20 15:55:23 +01:00
Patrick Niklaus 4684d2e35c Add changelog entry for changed behavior 2017-10-20 15:55:23 +01:00
Patrick Niklaus 27a9603b98 Change --use-location-cache=false to --disbale-location-cache 2017-10-20 15:55:23 +01:00
Patrick Niklaus 1610ea8dee Fix tests 2017-10-20 15:55:23 +01:00
Patrick Niklaus 171ff1191f Replace use of implicit_value since that broke with boost 1.65 2017-10-20 15:55:23 +01:00
karenzshea b5f9ba63d5 add code of conduct 2017-10-20 15:55:05 +01:00
Daniel J. Hofmann a3c0f6a4e2 Adds exception for barrier=lift_gate (bike, walk), resolves #4490 2017-10-19 15:27:35 +01:00
David Audrain 963c042b2a Run scripts/format.sh 2017-10-19 15:26:37 +01:00
David Audrain 1be7dedda7 Set missing OSM Node ID to zero instead of SPECIAL NODE ID 2017-10-19 15:26:37 +01:00
David Audrain 493a9a1cb2 Add 'to' and 'from' OSM Node Ids in the result of nearest webservice. #2548 2017-10-19 15:26:37 +01:00
Denis Koronchik e1149bd4b7 Review fixes 2017-10-19 15:18:25 +01:00
Denis Koronchik 895f072425 Work on forward/backward ref's support 2017-10-19 15:18:25 +01:00
96 changed files with 3824 additions and 716 deletions
+2
View File
@@ -0,0 +1,2 @@
test
build
+48
View File
@@ -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
View File
@@ -1,15 +1,50 @@
# UNRELEASED
# 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
View File
@@ -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(
+3
View File
@@ -0,0 +1,3 @@
# Code of conduct
Everyone is invited to participate in Project OSRMs 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
View File
@@ -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
-1
View File
@@ -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
+5
View File
@@ -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
View File
@@ -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
View File
@@ -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
View File
@@ -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
View File
@@ -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
+1
View File
@@ -10,6 +10,7 @@ Feature: Barriers
| | x |
| bollard | x |
| gate | x |
| lift_gate | x |
| cycle_barrier | x |
| cattle_grid | x |
| border_control | x |
+10 -9
View File
@@ -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
View File
@@ -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"
+120 -23
View File
@@ -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 |
+20 -20
View File
@@ -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 |
+5 -5
View File
@@ -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
+1
View File
@@ -10,6 +10,7 @@ Feature: Barriers
| | x |
| bollard | x |
| gate | x |
| lift_gate | x |
| cycle_barrier | x |
| cattle_grid | x |
| border_control | x |
+1 -1
View File
@@ -47,7 +47,7 @@ Feature: Turn Lane Guidance
e
a . . b . . . c g
` .
` .
` .
` d
f
"""
+50
View File
@@ -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 |
+159 -23
View File
@@ -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 |
+21
View File
@@ -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 |
+30
View File
@@ -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
+1 -1
View File
@@ -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
+5 -3
View File
@@ -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
+3 -3
View File
@@ -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
"""
+4
View File
@@ -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(',') + ']');
};
+7 -1
View File
@@ -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];
+19 -27
View File
@@ -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)));
}
-14
View File
@@ -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
*/
+43 -1
View File
@@ -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;
};
}
}
+15 -4
View File
@@ -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)
+4 -1
View File
@@ -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
+5
View File
@@ -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
+2 -1
View File
@@ -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
+12 -20
View File
@@ -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;
};
}
}
+12 -8
View File
@@ -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;
+9
View File
@@ -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);
};
}
}
+2 -1
View File
@@ -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;
+1
View File
@@ -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)
{
}
+1 -1
View File
@@ -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
+10
View File
@@ -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
+2 -5
View File
@@ -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];
+4 -3
View File
@@ -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,
+53 -2
View File
@@ -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 */
+14 -16
View File
@@ -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)
{
}
+1
View File
@@ -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) << " "
+3
View File
@@ -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
View File
@@ -1,6 +1,6 @@
{
"name": "osrm",
"version": "5.13.0-latest.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": {
+1
View File
@@ -48,6 +48,7 @@ function setup()
'toll_booth',
'sally_port',
'gate',
'lift_gate',
'no',
'block'
},
+7 -31
View File
@@ -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
+1
View File
@@ -33,6 +33,7 @@ function setup()
'toll_booth',
'sally_port',
'gate',
'lift_gate',
'no',
'kerb',
'block'
+66 -7
View File
@@ -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
+1 -1
View File
@@ -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
+9 -128
View File
@@ -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());
+13 -10
View File
@@ -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
View File
@@ -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);
+16 -3
View File
@@ -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
+239
View File
@@ -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 &current,
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 = [&current](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
+66 -57
View File
@@ -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,
+6 -1
View File
@@ -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.
+14 -1
View File
@@ -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;
}
+67 -20
View File
@@ -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()
+175 -110
View File
@@ -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;
+1 -1
View File
@@ -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 "
+6 -6
View File
@@ -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
+1 -1
View File
@@ -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
+5
View File
@@ -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
View File
@@ -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>
+2 -1
View File
@@ -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
+5
View File
@@ -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);
}
}
+2
View File
@@ -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},
+2 -1
View File
@@ -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
{