Compare commits
106 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
| 8250cd0f10 | |||
| 631c9f2360 | |||
| d8741a39e3 | |||
| d33ff6a897 | |||
| 85515f063a | |||
| 69d7825542 | |||
| 9b779c704f | |||
| 5bd7d04fe3 | |||
| 0f78f7b2cc | |||
| 8473be69d2 | |||
| c0124f7d77 | |||
| b630b4e32a | |||
| 89fabc1b9c | |||
| a649a8a5cf | |||
| f928956584 | |||
| 7ff68792d7 | |||
| 3088dd0342 | |||
| d2590989f5 | |||
| 3a7b377586 | |||
| 82b5648c97 | |||
| 1628a3c4d5 | |||
| e5d8319c43 | |||
| 06699132eb | |||
| 918e794d6a | |||
| 8dd8ee1fc2 | |||
| c3d0efda93 | |||
| 3b4e2e83ef | |||
| c459530cb6 | |||
| 2a15e6dec8 | |||
| 1a1293608d | |||
| 318df9deaa | |||
| cacb162520 | |||
| 105709cb43 | |||
| 9695fa7941 | |||
| fd9bebbfa7 | |||
| db18e8669f | |||
| 9b4a4fdd82 | |||
| cdc7e5f021 | |||
| adc87149e2 | |||
| 8adbfe06ed | |||
| ae805f9ec8 | |||
| be24689b0f | |||
| 41c31a2388 | |||
| 8b866502d1 | |||
| 7837cd61df | |||
| b573485c31 | |||
| 4e68f3a7e1 | |||
| 5ba26d3d6d | |||
| a6cf2eee7e | |||
| 6843eb1479 | |||
| b331885d3c | |||
| 73716bd651 | |||
| 9edd161da3 | |||
| 1bc3ff6491 | |||
| b0f2ef287e | |||
| 16f53ff81a | |||
| 7a260dc2ba | |||
| 1c0d951f5e | |||
| 77a740c0fb | |||
| 61101db8cf | |||
| b51632a2fb | |||
| 9d10503a9c | |||
| 7d50e5afe0 | |||
| 549216c792 | |||
| 1990de7dcc | |||
| 89f6e2d55b | |||
| c628ecbf24 | |||
| b6f19cd544 | |||
| 14860b62e9 | |||
| 9970b7d580 | |||
| 7feb79ef91 | |||
| 6f84812903 | |||
| 8085e86170 | |||
| 35973576d9 | |||
| 7740d5d7c0 | |||
| c4eff6cd65 | |||
| 5c4353b46e | |||
| 05a5918909 | |||
| 80ad38bbc6 | |||
| 6bee8866de | |||
| ba92674c6e | |||
| 68019a1fb2 | |||
| 3a9acde2c3 | |||
| a3a7a822e1 | |||
| c7d22c2b92 | |||
| b2aeb47630 | |||
| 0a1d1901cc | |||
| 29db0c80d9 | |||
| 4654751872 | |||
| b5b18d8afc | |||
| 15139c934f | |||
| 7b8619e37c | |||
| f52b5c31b6 | |||
| e98859e4c0 | |||
| c5cc4c5a74 | |||
| e3b831364f | |||
| 730d2b5ef2 | |||
| 16abee1022 | |||
| 69fa52a010 | |||
| e1efa4c6ab | |||
| 17cd1575f6 | |||
| 3cd8e0fef8 | |||
| 397bb694fd | |||
| 473ebfcbf6 | |||
| a06171438e | |||
| ea0881553e |
@@ -1,4 +1,32 @@
|
|||||||
# UNRELEASED
|
# UNRELEASED
|
||||||
|
- Changes from 5.18.0:
|
||||||
|
- Optimizations:
|
||||||
|
- CHANGED: Map matching is now almost twice as fast. [#5060](https://github.com/Project-OSRM/osrm-backend/pull/5060)
|
||||||
|
- CHANGED: Use Grisu2 for serializing floating point numbers. [#5188](https://github.com/Project-OSRM/osrm-backend/pull/5188)
|
||||||
|
- Bugfixes:
|
||||||
|
- FIXED: collapsing of ExitRoundabout instructions [#5114](https://github.com/Project-OSRM/osrm-backend/issues/5114)
|
||||||
|
- FIXED: negative distances in table plugin annotation [#5106](https://github.com/Project-OSRM/osrm-backend/issues/5106)
|
||||||
|
- Misc:
|
||||||
|
- CHANGED: Support up to 512 named shared memory regions [#5185](https://github.com/Project-OSRM/osrm-backend/pull/5185)
|
||||||
|
|
||||||
|
# 5.18.0
|
||||||
|
- Changes from 5.17.0:
|
||||||
|
- Features:
|
||||||
|
- ADDED: `table` plugin now optionally returns `distance` matrix as part of response [#4990](https://github.com/Project-OSRM/osrm-backend/pull/4990)
|
||||||
|
- ADDED: New optional parameter `annotations` for `table` that accepts `distance`, `duration`, or both `distance,duration` as values [#4990](https://github.com/Project-OSRM/osrm-backend/pull/4990)
|
||||||
|
- Infrastructure:
|
||||||
|
- ADDED: Updated libosmium and added protozero and vtzero libraries [#5037](https://github.com/Project-OSRM/osrm-backend/pull/5037)
|
||||||
|
- CHANGED: Use vtzero library in tile plugin [#4686](https://github.com/Project-OSRM/osrm-backend/pull/4686)
|
||||||
|
- Profile:
|
||||||
|
- ADDED: Bicycle profile now returns classes for ferry and tunnel routes. [#5054](https://github.com/Project-OSRM/osrm-backend/pull/5054)
|
||||||
|
- ADDED: Bicycle profile allows to exclude ferry routes (default to not enabled) [#5054](https://github.com/Project-OSRM/osrm-backend/pull/5054)
|
||||||
|
|
||||||
|
# 5.17.1
|
||||||
|
- Changes from 5.17.0:
|
||||||
|
- Bugfixes:
|
||||||
|
- FIXED: Do not combine a segregated edge with a roundabout [#5039](https://github.com/Project-OSRM/osrm-backend/issues/5039)
|
||||||
|
|
||||||
|
# 5.17.0
|
||||||
- Changes from 5.16.0:
|
- Changes from 5.16.0:
|
||||||
- Bugfixes:
|
- Bugfixes:
|
||||||
- FIXED: deduplication of route steps when waypoints are used [#4909](https://github.com/Project-OSRM/osrm-backend/issues/4909)
|
- FIXED: deduplication of route steps when waypoints are used [#4909](https://github.com/Project-OSRM/osrm-backend/issues/4909)
|
||||||
@@ -6,9 +34,11 @@
|
|||||||
- FIXED: Remove the last short annotation segment in `trimShortSegments` [#4946](https://github.com/Project-OSRM/osrm-backend/pull/4946)
|
- FIXED: Remove the last short annotation segment in `trimShortSegments` [#4946](https://github.com/Project-OSRM/osrm-backend/pull/4946)
|
||||||
- FIXED: Properly calculate annotations for speeds, durations and distances when waypoints are used with mapmatching [#4949](https://github.com/Project-OSRM/osrm-backend/pull/4949)
|
- FIXED: Properly calculate annotations for speeds, durations and distances when waypoints are used with mapmatching [#4949](https://github.com/Project-OSRM/osrm-backend/pull/4949)
|
||||||
- FIXED: Don't apply unimplemented SH and PH conditions in OpeningHours and add inversed date ranges [#4992](https://github.com/Project-OSRM/osrm-backend/issues/4992)
|
- FIXED: Don't apply unimplemented SH and PH conditions in OpeningHours and add inversed date ranges [#4992](https://github.com/Project-OSRM/osrm-backend/issues/4992)
|
||||||
|
- FIXED: integer overflow in `DynamicGraph::Renumber` [#5021](https://github.com/Project-OSRM/osrm-backend/pull/5021)
|
||||||
- Profile:
|
- Profile:
|
||||||
- CHANGED: Handle oneways in get_forward_backward_by_key [#4929](https://github.com/Project-OSRM/osrm-backend/pull/4929)
|
- CHANGED: Handle oneways in get_forward_backward_by_key [#4929](https://github.com/Project-OSRM/osrm-backend/pull/4929)
|
||||||
- FIXED: Do not route against oneway road if there is a cycleway in the wrong direction; also review bike profile [#4943](https://github.com/Project-OSRM/osrm-backend/issues/4943)
|
- FIXED: Do not route against oneway road if there is a cycleway in the wrong direction; also review bike profile [#4943](https://github.com/Project-OSRM/osrm-backend/issues/4943)
|
||||||
|
- CHANGED: Make cyclability weighting of the bike profile prefer safer routes more strongly [#5015](https://github.com/Project-OSRM/osrm-backend/issues/5015)
|
||||||
- Guidance:
|
- Guidance:
|
||||||
- CHANGED: Don't use obviousness for links bifurcations [#4929](https://github.com/Project-OSRM/osrm-backend/pull/4929)
|
- CHANGED: Don't use obviousness for links bifurcations [#4929](https://github.com/Project-OSRM/osrm-backend/pull/4929)
|
||||||
- FIXED: Adjust Straight direction modifiers of side roads in driveway handler [#4929](https://github.com/Project-OSRM/osrm-backend/pull/4929)
|
- FIXED: Adjust Straight direction modifiers of side roads in driveway handler [#4929](https://github.com/Project-OSRM/osrm-backend/pull/4929)
|
||||||
|
|||||||
+23
-12
@@ -167,7 +167,7 @@ add_executable(osrm-customize src/tools/customize.cpp)
|
|||||||
add_executable(osrm-contract src/tools/contract.cpp)
|
add_executable(osrm-contract src/tools/contract.cpp)
|
||||||
add_executable(osrm-routed src/tools/routed.cpp $<TARGET_OBJECTS:SERVER> $<TARGET_OBJECTS:UTIL>)
|
add_executable(osrm-routed src/tools/routed.cpp $<TARGET_OBJECTS:SERVER> $<TARGET_OBJECTS:UTIL>)
|
||||||
add_executable(osrm-datastore src/tools/store.cpp $<TARGET_OBJECTS:MICROTAR> $<TARGET_OBJECTS:UTIL>)
|
add_executable(osrm-datastore src/tools/store.cpp $<TARGET_OBJECTS:MICROTAR> $<TARGET_OBJECTS:UTIL>)
|
||||||
add_library(osrm src/osrm/osrm.cpp $<TARGET_OBJECTS:ENGINE> $<TARGET_OBJECTS:STORAGE> $<TARGET_OBJECTS:MICROTAR> $<TARGET_OBJECTS:UTIL> )
|
add_library(osrm src/osrm/osrm.cpp $<TARGET_OBJECTS:ENGINE> $<TARGET_OBJECTS:STORAGE> $<TARGET_OBJECTS:MICROTAR> $<TARGET_OBJECTS:UTIL>)
|
||||||
add_library(osrm_contract src/osrm/contractor.cpp $<TARGET_OBJECTS:CONTRACTOR> $<TARGET_OBJECTS:UTIL>)
|
add_library(osrm_contract src/osrm/contractor.cpp $<TARGET_OBJECTS:CONTRACTOR> $<TARGET_OBJECTS:UTIL>)
|
||||||
add_library(osrm_extract src/osrm/extractor.cpp $<TARGET_OBJECTS:EXTRACTOR> $<TARGET_OBJECTS:MICROTAR> $<TARGET_OBJECTS:UTIL>)
|
add_library(osrm_extract src/osrm/extractor.cpp $<TARGET_OBJECTS:EXTRACTOR> $<TARGET_OBJECTS:MICROTAR> $<TARGET_OBJECTS:UTIL>)
|
||||||
add_library(osrm_guidance $<TARGET_OBJECTS:GUIDANCE> $<TARGET_OBJECTS:UTIL>)
|
add_library(osrm_guidance $<TARGET_OBJECTS:GUIDANCE> $<TARGET_OBJECTS:UTIL>)
|
||||||
@@ -416,11 +416,30 @@ if(UNIX AND NOT APPLE)
|
|||||||
set(MAYBE_RT_LIBRARY -lrt)
|
set(MAYBE_RT_LIBRARY -lrt)
|
||||||
endif()
|
endif()
|
||||||
|
|
||||||
# Disallow deprecated protozero APIs
|
|
||||||
add_definitions(-DPROTOZERO_STRICT_API)
|
|
||||||
|
|
||||||
find_package(Threads REQUIRED)
|
find_package(Threads REQUIRED)
|
||||||
|
|
||||||
|
# Third-party libraries
|
||||||
|
set(RAPIDJSON_INCLUDE_DIR "${CMAKE_CURRENT_SOURCE_DIR}/third_party/rapidjson/include")
|
||||||
|
include_directories(SYSTEM ${RAPIDJSON_INCLUDE_DIR})
|
||||||
|
|
||||||
|
set(MICROTAR_INCLUDE_DIR "${CMAKE_CURRENT_SOURCE_DIR}/third_party/microtar/src")
|
||||||
|
include_directories(SYSTEM ${MICROTAR_INCLUDE_DIR})
|
||||||
|
|
||||||
|
set(MBXGEOM_INCLUDE_DIR "${CMAKE_CURRENT_SOURCE_DIR}/third_party/geometry.hpp-0.9.2/include")
|
||||||
|
include_directories(SYSTEM ${MBXGEOM_INCLUDE_DIR})
|
||||||
|
set(CHEAPRULER_INCLUDE_DIR "${CMAKE_CURRENT_SOURCE_DIR}/third_party/cheap-ruler-cpp-2.5.4/include")
|
||||||
|
include_directories(SYSTEM ${CHEAPRULER_INCLUDE_DIR})
|
||||||
|
|
||||||
|
add_library(MICROTAR OBJECT "${CMAKE_CURRENT_SOURCE_DIR}/third_party/microtar/src/microtar.c")
|
||||||
|
set_property(TARGET MICROTAR PROPERTY POSITION_INDEPENDENT_CODE ON)
|
||||||
|
|
||||||
|
set(PROTOZERO_INCLUDE_DIR "${CMAKE_CURRENT_SOURCE_DIR}/third_party/protozero/include")
|
||||||
|
include_directories(SYSTEM ${PROTOZERO_INCLUDE_DIR})
|
||||||
|
|
||||||
|
set(VTZERO_INCLUDE_DIR "${CMAKE_CURRENT_SOURCE_DIR}/third_party/vtzero/include")
|
||||||
|
include_directories(SYSTEM ${VTZERO_INCLUDE_DIR})
|
||||||
|
|
||||||
|
|
||||||
# if mason is enabled no find_package calls are made
|
# if mason is enabled no find_package calls are made
|
||||||
# to ensure that we are only compiling and linking against
|
# to ensure that we are only compiling and linking against
|
||||||
# fully portable mason packages
|
# fully portable mason packages
|
||||||
@@ -554,14 +573,6 @@ else()
|
|||||||
include_directories(SYSTEM ${OSMIUM_INCLUDE_DIR})
|
include_directories(SYSTEM ${OSMIUM_INCLUDE_DIR})
|
||||||
endif()
|
endif()
|
||||||
|
|
||||||
set(RAPIDJSON_INCLUDE_DIR "${CMAKE_CURRENT_SOURCE_DIR}/third_party/rapidjson/include")
|
|
||||||
include_directories(SYSTEM ${RAPIDJSON_INCLUDE_DIR})
|
|
||||||
|
|
||||||
set(MICROTAR_INCLUDE_DIR "${CMAKE_CURRENT_SOURCE_DIR}/third_party/microtar/src")
|
|
||||||
include_directories(SYSTEM ${MICROTAR_INCLUDE_DIR})
|
|
||||||
add_library(MICROTAR OBJECT "${CMAKE_CURRENT_SOURCE_DIR}/third_party/microtar/src/microtar.c")
|
|
||||||
set_property(TARGET MICROTAR PROPERTY POSITION_INDEPENDENT_CODE ON)
|
|
||||||
|
|
||||||
# prefix compilation with ccache by default if available and on clang or gcc
|
# prefix compilation with ccache by default if available and on clang or gcc
|
||||||
if(ENABLE_CCACHE AND (CMAKE_CXX_COMPILER_ID MATCHES "Clang" OR CMAKE_CXX_COMPILER_ID MATCHES "GNU"))
|
if(ENABLE_CCACHE AND (CMAKE_CXX_COMPILER_ID MATCHES "Clang" OR CMAKE_CXX_COMPILER_ID MATCHES "GNU"))
|
||||||
find_program(CCACHE_FOUND ccache)
|
find_program(CCACHE_FOUND ccache)
|
||||||
|
|||||||
@@ -9,7 +9,7 @@ High performance routing engine written in C++14 designed to run on OpenStreetMa
|
|||||||
The following services are available via HTTP API, C++ library interface and NodeJs wrapper:
|
The following services are available via HTTP API, C++ library interface and NodeJs wrapper:
|
||||||
- Nearest - Snaps coordinates to the street network and returns the nearest matches
|
- Nearest - Snaps coordinates to the street network and returns the nearest matches
|
||||||
- Route - Finds the fastest route between coordinates
|
- Route - Finds the fastest route between coordinates
|
||||||
- Table - Computes the duration of the fastest route between all pairs of supplied coordinates
|
- Table - Computes the duration or distances of the fastest route between all pairs of supplied coordinates
|
||||||
- Match - Snaps noisy GPS traces to the road network in the most plausible way
|
- Match - Snaps noisy GPS traces to the road network in the most plausible way
|
||||||
- Trip - Solves the Traveling Salesman Problem using a greedy heuristic
|
- Trip - Solves the Traveling Salesman Problem using a greedy heuristic
|
||||||
- Tile - Generates Mapbox Vector Tiles with internal routing metadata
|
- Tile - Generates Mapbox Vector Tiles with internal routing metadata
|
||||||
|
|||||||
+1
-1
@@ -3,5 +3,5 @@ module.exports = {
|
|||||||
verify: '--strict --tags ~@stress --tags ~@todo --tags ~@mld-only -f progress --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',
|
todo: '--strict --tags @todo --require features/support --require features/step_definitions',
|
||||||
all: '--strict --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'
|
mld: '--strict --tags ~@stress --tags ~@todo --tags ~@ch --require features/support --require features/step_definitions -f progress'
|
||||||
};
|
};
|
||||||
|
|||||||
+117
-8
@@ -222,13 +222,13 @@ curl 'http://router.project-osrm.org/route/v1/driving/13.388860,52.517037;13.397
|
|||||||
|
|
||||||
### Table service
|
### Table service
|
||||||
|
|
||||||
Computes the duration of the fastest route between all pairs of supplied coordinates.
|
Computes the duration of the fastest route between all pairs of supplied coordinates. Returns the durations or distances or both between the coordinate pairs. Note that the distances are not the shortest distance between two coordinates, but rather the distances of the fastest routes. Duration is in seconds and distances is in meters.
|
||||||
|
|
||||||
```endpoint
|
```endpoint
|
||||||
GET /table/v1/{profile}/{coordinates}?{sources}=[{elem}...];&destinations=[{elem}...]
|
GET /table/v1/{profile}/{coordinates}?{sources}=[{elem}...];&{destinations}=[{elem}...]&annotations={duration|distance|duration,distance}
|
||||||
```
|
```
|
||||||
|
|
||||||
**Coordinates**
|
**Options**
|
||||||
|
|
||||||
In addition to the [general options](#general-options) the following options are supported for this service:
|
In addition to the [general options](#general-options) the following options are supported for this service:
|
||||||
|
|
||||||
@@ -236,6 +236,8 @@ In addition to the [general options](#general-options) the following options are
|
|||||||
|------------|--------------------------------------------------|---------------------------------------------|
|
|------------|--------------------------------------------------|---------------------------------------------|
|
||||||
|sources |`{index};{index}[;{index} ...]` or `all` (default)|Use location with given index as source. |
|
|sources |`{index};{index}[;{index} ...]` or `all` (default)|Use location with given index as source. |
|
||||||
|destinations|`{index};{index}[;{index} ...]` or `all` (default)|Use location with given index as destination.|
|
|destinations|`{index};{index}[;{index} ...]` or `all` (default)|Use location with given index as destination.|
|
||||||
|
|annotations |`duration` (default), `distance`, or `duration,distance`|Return the requested table or tables in response. Note that computing the `distances` table is currently only implemented for CH. If `annotations=distance` or `annotations=duration,distance` is requested when running a MLD router, a `NotImplemented` error will be returned.
|
||||||
|
|
|
||||||
|
|
||||||
Unlike other array encoded options, the length of `sources` and `destinations` can be **smaller or equal**
|
Unlike other array encoded options, the length of `sources` and `destinations` can be **smaller or equal**
|
||||||
to number of input locations;
|
to number of input locations;
|
||||||
@@ -253,14 +255,23 @@ sources=0;5;7&destinations=5;1;4;2;3;6
|
|||||||
#### Example Request
|
#### Example Request
|
||||||
|
|
||||||
```curl
|
```curl
|
||||||
# Returns a 3x3 matrix:
|
# Returns a 3x3 duration matrix:
|
||||||
curl 'http://router.project-osrm.org/table/v1/driving/13.388860,52.517037;13.397634,52.529407;13.428555,52.523219'
|
curl 'http://router.project-osrm.org/table/v1/driving/13.388860,52.517037;13.397634,52.529407;13.428555,52.523219'
|
||||||
|
|
||||||
# Returns a 1x3 matrix
|
# Returns a 1x3 duration matrix
|
||||||
curl 'http://router.project-osrm.org/table/v1/driving/13.388860,52.517037;13.397634,52.529407;13.428555,52.523219?sources=0'
|
curl 'http://router.project-osrm.org/table/v1/driving/13.388860,52.517037;13.397634,52.529407;13.428555,52.523219?sources=0'
|
||||||
|
|
||||||
# Returns a asymmetric 3x2 matrix with from the polyline encoded locations `qikdcB}~dpXkkHz`:
|
# Returns a asymmetric 3x2 duration matrix with from the polyline encoded locations `qikdcB}~dpXkkHz`:
|
||||||
curl 'http://router.project-osrm.org/table/v1/driving/polyline(egs_Iq_aqAppHzbHulFzeMe`EuvKpnCglA)?sources=0;1;3&destinations=2;4'
|
curl 'http://router.project-osrm.org/table/v1/driving/polyline(egs_Iq_aqAppHzbHulFzeMe`EuvKpnCglA)?sources=0;1;3&destinations=2;4'
|
||||||
|
|
||||||
|
# Returns a 3x3 duration matrix:
|
||||||
|
curl 'http://router.project-osrm.org/table/v1/driving/13.388860,52.517037;13.397634,52.529407;13.428555,52.523219?annotations=duration'
|
||||||
|
|
||||||
|
# Returns a 3x3 distance matrix for CH:
|
||||||
|
curl 'http://router.project-osrm.org/table/v1/driving/13.388860,52.517037;13.397634,52.529407;13.428555,52.523219?annotations=distance'
|
||||||
|
|
||||||
|
# Returns a 3x3 duration matrix and a 3x3 distance matrix for CH:
|
||||||
|
curl 'http://router.project-osrm.org/table/v1/driving/13.388860,52.517037;13.397634,52.529407;13.428555,52.523219?annotations=distance,duration'
|
||||||
```
|
```
|
||||||
|
|
||||||
**Response**
|
**Response**
|
||||||
@@ -268,17 +279,115 @@ curl 'http://router.project-osrm.org/table/v1/driving/polyline(egs_Iq_aqAppHzbHu
|
|||||||
- `code` if the request was successful `Ok` otherwise see the service dependent and general status codes.
|
- `code` if the request was successful `Ok` otherwise see the service dependent and general status codes.
|
||||||
- `durations` array of arrays that stores the matrix in row-major order. `durations[i][j]` gives the travel time from
|
- `durations` array of arrays that stores the matrix in row-major order. `durations[i][j]` gives the travel time from
|
||||||
the i-th waypoint to the j-th waypoint. Values are given in seconds. Can be `null` if no route between `i` and `j` can be found.
|
the i-th waypoint to the j-th waypoint. Values are given in seconds. Can be `null` if no route between `i` and `j` can be found.
|
||||||
|
- `distances` array of arrays that stores the matrix in row-major order. `distances[i][j]` gives the travel distance from
|
||||||
|
the i-th waypoint to the j-th waypoint. Values are given in meters. Can be `null` if no route between `i` and `j` can be found. Note that computing the `distances` table is currently only implemented for CH. If `annotations=distance` or `annotations=duration,distance` is requested when running a MLD router, a `NotImplemented` error will be returned.
|
||||||
- `sources` array of `Waypoint` objects describing all sources in order
|
- `sources` array of `Waypoint` objects describing all sources in order
|
||||||
- `destinations` array of `Waypoint` objects describing all destinations in order
|
- `destinations` array of `Waypoint` objects describing all destinations in order
|
||||||
|
|
||||||
In case of error the following `code`s are supported in addition to the general ones:
|
In case of error the following `code`s are supported in addition to the general ones:
|
||||||
|
|
||||||
| Type | Description |
|
| Type | Description |
|
||||||
|-------------------|-----------------|
|
|------------------|-----------------|
|
||||||
| `NoTable` | No route found. |
|
| `NoTable` | No route found. |
|
||||||
|
| `NotImplemented` | This request is not supported |
|
||||||
|
|
||||||
All other properties might be undefined.
|
All other properties might be undefined.
|
||||||
|
|
||||||
|
#### Example Response
|
||||||
|
|
||||||
|
```json
|
||||||
|
{
|
||||||
|
"sources": [
|
||||||
|
{
|
||||||
|
"location": [
|
||||||
|
13.3888,
|
||||||
|
52.517033
|
||||||
|
],
|
||||||
|
"hint": "PAMAgEVJAoAUAAAAIAAAAAcAAAAAAAAArss0Qa7LNEHiVIRA4lSEQAoAAAAQAAAABAAAAAAAAADMAAAAAEzMAKlYIQM8TMwArVghAwEA3wps52D3",
|
||||||
|
"name": "Friedrichstraße"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"location": [
|
||||||
|
13.397631,
|
||||||
|
52.529432
|
||||||
|
],
|
||||||
|
"hint": "WIQBgL6mAoAEAAAABgAAAAAAAAA7AAAAhU6PQHvHj0IAAAAAQbyYQgQAAAAGAAAAAAAAADsAAADMAAAAf27MABiJIQOCbswA_4ghAwAAXwVs52D3",
|
||||||
|
"name": "Torstraße"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"location": [
|
||||||
|
13.428554,
|
||||||
|
52.523239
|
||||||
|
],
|
||||||
|
"hint": "7UcAgP___38fAAAAUQAAACYAAABTAAAAhSQKQrXq5kKRbiZCWJo_Qx8AAABRAAAAJgAAAFMAAADMAAAASufMAOdwIQNL58wA03AhAwMAvxBs52D3",
|
||||||
|
"name": "Platz der Vereinten Nationen"
|
||||||
|
}
|
||||||
|
],
|
||||||
|
"durations": [
|
||||||
|
[
|
||||||
|
0,
|
||||||
|
192.6,
|
||||||
|
382.8
|
||||||
|
],
|
||||||
|
[
|
||||||
|
199,
|
||||||
|
0,
|
||||||
|
283.9
|
||||||
|
],
|
||||||
|
[
|
||||||
|
344.7,
|
||||||
|
222.3,
|
||||||
|
0
|
||||||
|
]
|
||||||
|
],
|
||||||
|
"destinations": [
|
||||||
|
{
|
||||||
|
"location": [
|
||||||
|
13.3888,
|
||||||
|
52.517033
|
||||||
|
],
|
||||||
|
"hint": "PAMAgEVJAoAUAAAAIAAAAAcAAAAAAAAArss0Qa7LNEHiVIRA4lSEQAoAAAAQAAAABAAAAAAAAADMAAAAAEzMAKlYIQM8TMwArVghAwEA3wps52D3",
|
||||||
|
"name": "Friedrichstraße"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"location": [
|
||||||
|
13.397631,
|
||||||
|
52.529432
|
||||||
|
],
|
||||||
|
"hint": "WIQBgL6mAoAEAAAABgAAAAAAAAA7AAAAhU6PQHvHj0IAAAAAQbyYQgQAAAAGAAAAAAAAADsAAADMAAAAf27MABiJIQOCbswA_4ghAwAAXwVs52D3",
|
||||||
|
"name": "Torstraße"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"location": [
|
||||||
|
13.428554,
|
||||||
|
52.523239
|
||||||
|
],
|
||||||
|
"hint": "7UcAgP___38fAAAAUQAAACYAAABTAAAAhSQKQrXq5kKRbiZCWJo_Qx8AAABRAAAAJgAAAFMAAADMAAAASufMAOdwIQNL58wA03AhAwMAvxBs52D3",
|
||||||
|
"name": "Platz der Vereinten Nationen"
|
||||||
|
}
|
||||||
|
],
|
||||||
|
"code": "Ok",
|
||||||
|
"distances": [
|
||||||
|
[
|
||||||
|
0,
|
||||||
|
1886.89,
|
||||||
|
3791.3
|
||||||
|
],
|
||||||
|
[
|
||||||
|
1824,
|
||||||
|
0,
|
||||||
|
2838.09
|
||||||
|
],
|
||||||
|
[
|
||||||
|
3275.36,
|
||||||
|
2361.73,
|
||||||
|
0
|
||||||
|
]
|
||||||
|
]
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
|
|
||||||
### Match service
|
### Match service
|
||||||
|
|
||||||
Map matching matches/snaps given GPS points to the road network in the most plausible way.
|
Map matching matches/snaps given GPS points to the road network in the most plausible way.
|
||||||
|
|||||||
+2
-2
@@ -110,8 +110,8 @@ Returns **[Object](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Refer
|
|||||||
|
|
||||||
### table
|
### table
|
||||||
|
|
||||||
Computes duration tables for the given locations. Allows for both symmetric and asymmetric
|
Computes duration table for the given locations. Allows for both symmetric and asymmetric
|
||||||
tables.
|
tables. Optionally returns distance table.
|
||||||
|
|
||||||
**Parameters**
|
**Parameters**
|
||||||
|
|
||||||
|
|||||||
+5
-5
@@ -68,7 +68,7 @@ If you want to prioritize certain streets, increase the rate on these.
|
|||||||
|
|
||||||
## Elements
|
## Elements
|
||||||
### api_version
|
### api_version
|
||||||
A profile should set `api_version` at the top of your profile. This is done to ensure that older profiles are still supported when the api changes. If `api_version` is not defined, 0 will be assumed. The current api version is 2.
|
A profile should set `api_version` at the top of your profile. This is done to ensure that older profiles are still supported when the api changes. If `api_version` is not defined, 0 will be assumed. The current api version is 4.
|
||||||
|
|
||||||
### Library files
|
### Library files
|
||||||
The folder [profiles/lib/](../profiles/lib/) contains LUA library files for handling many common processing tasks.
|
The folder [profiles/lib/](../profiles/lib/) contains LUA library files for handling many common processing tasks.
|
||||||
@@ -138,7 +138,7 @@ Given an OpenStreetMap way, the `process_way` function will either return nothin
|
|||||||
Argument | Description
|
Argument | Description
|
||||||
---------|-------------------------------------------------------
|
---------|-------------------------------------------------------
|
||||||
profile | The configuration table you returned in `setup`.
|
profile | The configuration table you returned in `setup`.
|
||||||
node | The input way to process (read-only).
|
way | The input way to process (read-only).
|
||||||
result | The output that you will modify.
|
result | The output that you will modify.
|
||||||
relations| Storage of relations to access relations, where `way` is a member.
|
relations| Storage of relations to access relations, where `way` is a member.
|
||||||
|
|
||||||
@@ -199,7 +199,7 @@ source.lon | Read | Float | Co-ordinates of segment start
|
|||||||
source.lat | Read | Float | ""
|
source.lat | Read | Float | ""
|
||||||
target.lon | Read | Float | Co-ordinates of segment end
|
target.lon | Read | Float | Co-ordinates of segment end
|
||||||
target.lat | Read | Float | ""
|
target.lat | Read | Float | ""
|
||||||
target.distance | Read | Float | Length of segment
|
distance | Read | Float | Length of segment
|
||||||
weight | Read/write | Float | Routing weight for this segment
|
weight | Read/write | Float | Routing weight for this segment
|
||||||
duration | Read/write | Float | Duration for this segment
|
duration | Read/write | Float | Duration for this segment
|
||||||
|
|
||||||
@@ -224,8 +224,8 @@ source_highway_turn_classification | Read | Integer |
|
|||||||
source_access_turn_classification | Read | Integer | Classification based on access tag defined by user during setup. (default when not set: 0, allowed classification values are: 0-15))
|
source_access_turn_classification | Read | Integer | Classification based on access tag defined by user during setup. (default when not set: 0, allowed classification values are: 0-15))
|
||||||
source_speed | Read | Integer | Speed on this source road in km/h
|
source_speed | Read | Integer | Speed on this source road in km/h
|
||||||
source_priority_class | Read | Enum | The type of road priority class of the source. Defined in `include/extractor/guidance/road_classification.hpp`
|
source_priority_class | Read | Enum | The type of road priority class of the source. Defined in `include/extractor/guidance/road_classification.hpp`
|
||||||
target_restricted | Read | Boolean | Is it from a restricted access road? (See definition in `process_way`)
|
target_restricted | Read | Boolean | Is the target a restricted access road? (See definition in `process_way`)
|
||||||
target_mode | Read | Enum | Travel mode before the turn. Defined in `include/extractor/travel_mode.hpp`
|
target_mode | Read | Enum | Travel mode after the turn. Defined in `include/extractor/travel_mode.hpp`
|
||||||
target_is_motorway | Read | Boolean | Is the target road a motorway?
|
target_is_motorway | Read | Boolean | Is the target road a motorway?
|
||||||
target_is_link | Read | Boolean | Is the target road a link?
|
target_is_link | Read | Boolean | Is the target road a link?
|
||||||
target_number_of_lanes | Read | Integer | How many lanes does the target road have? (default when not tagged: 0)
|
target_number_of_lanes | Read | Integer | How many lanes does the target road have? (default when not tagged: 0)
|
||||||
|
|||||||
+3
-3
@@ -43,9 +43,9 @@ We may introduce forward-compatible changes: query parameters and response prope
|
|||||||
|
|
||||||
1. Check out the appropriate release branch `x.y`
|
1. Check out the appropriate release branch `x.y`
|
||||||
2. Make sure `CHANGELOG.md` is up to date.
|
2. Make sure `CHANGELOG.md` is up to date.
|
||||||
3. Make sure the `package.json` is up to date.
|
3. Make sure the `package.json` on branch `x.y` has been committed.
|
||||||
4. Make sure all tests are passing (e.g. Travis CI gives you a :thumbs_up:)
|
4. Make sure all tests are passing (e.g. Travis CI gives you a :green_apple:)
|
||||||
5. Use an annotated tag to mark the release: `git tag vx.y.z -a` Body of the tag description should be the changelog entries.
|
5. Use an annotated tag to mark the release: `git tag vx.y.z -a` Body of the tag description should be the changelog entries. Commit should be one in which the `package.json` version matches the version you want to release.
|
||||||
6. Use `npm run docs` to generate the API documentation. Copy `build/docs/*` to `https://github.com/Project-OSRM/project-osrm.github.com` in the `docs/vN.N.N/api` directory
|
6. Use `npm run docs` to generate the API documentation. Copy `build/docs/*` to `https://github.com/Project-OSRM/project-osrm.github.com` in the `docs/vN.N.N/api` directory
|
||||||
7. Push tags and commits: `git push; git push --tags`
|
7. Push tags and commits: `git push; git push --tags`
|
||||||
8. On https://github.com/Project-OSRM/osrm-backend/releases press `Draft a new release`,
|
8. On https://github.com/Project-OSRM/osrm-backend/releases press `Draft a new release`,
|
||||||
|
|||||||
@@ -19,7 +19,7 @@ Feature: Barriers
|
|||||||
| entrance | x |
|
| entrance | x |
|
||||||
| wall | |
|
| wall | |
|
||||||
| fence | |
|
| fence | |
|
||||||
| some_tag | |
|
| some_tag | x |
|
||||||
| block | x |
|
| block | x |
|
||||||
|
|
||||||
Scenario: Bike - Access tag trumphs barriers
|
Scenario: Bike - Access tag trumphs barriers
|
||||||
|
|||||||
@@ -0,0 +1,92 @@
|
|||||||
|
@routing @bicycle @mode
|
||||||
|
Feature: Bicycle - Mode flag
|
||||||
|
Background:
|
||||||
|
Given the profile "bicycle"
|
||||||
|
|
||||||
|
Scenario: Bicycle - We tag ferries with a class
|
||||||
|
Given the node map
|
||||||
|
"""
|
||||||
|
a b
|
||||||
|
c d
|
||||||
|
"""
|
||||||
|
|
||||||
|
And the ways
|
||||||
|
| nodes | highway | route |
|
||||||
|
| ab | primary | |
|
||||||
|
| bc | | ferry |
|
||||||
|
| cd | primary | |
|
||||||
|
|
||||||
|
When I route I should get
|
||||||
|
| from | to | route | turns | classes |
|
||||||
|
| a | d | ab,bc,cd,cd | depart,notification right,notification left,arrive | [()],[(ferry)],[()],[()] |
|
||||||
|
| d | a | cd,bc,ab,ab | depart,notification right,notification left,arrive | [()],[(ferry)],[()],[()] |
|
||||||
|
| c | a | bc,ab,ab | depart,notification left,arrive | [(ferry)],[()],[()] |
|
||||||
|
| d | b | cd,bc,bc | depart,notification right,arrive | [()],[(ferry)],[()] |
|
||||||
|
| a | c | ab,bc,bc | depart,notification right,arrive | [()],[(ferry)],[()] |
|
||||||
|
| b | d | bc,cd,cd | depart,notification left,arrive | [(ferry)],[()],[()] |
|
||||||
|
|
||||||
|
Scenario: Bicycle - We tag tunnel with a class
|
||||||
|
Background:
|
||||||
|
Given a grid size of 200 meters
|
||||||
|
|
||||||
|
Given the node map
|
||||||
|
"""
|
||||||
|
a b
|
||||||
|
c d
|
||||||
|
"""
|
||||||
|
|
||||||
|
And the ways
|
||||||
|
| nodes | tunnel |
|
||||||
|
| ab | no |
|
||||||
|
| bc | yes |
|
||||||
|
| cd | |
|
||||||
|
|
||||||
|
When I route I should get
|
||||||
|
| from | to | route | turns | classes |
|
||||||
|
| a | d | ab,bc,cd,cd | depart,new name right,new name left,arrive | [()],[(tunnel)],[()],[()] |
|
||||||
|
|
||||||
|
Scenario: Bicycle - We tag classes without intersections
|
||||||
|
Background:
|
||||||
|
Given a grid size of 200 meters
|
||||||
|
|
||||||
|
Given the node map
|
||||||
|
"""
|
||||||
|
a b c d
|
||||||
|
"""
|
||||||
|
|
||||||
|
And the ways
|
||||||
|
| nodes | name | tunnel |
|
||||||
|
| ab | road | |
|
||||||
|
| bc | road | yes |
|
||||||
|
| cd | road | |
|
||||||
|
|
||||||
|
When I route I should get
|
||||||
|
| from | to | route | turns | classes |
|
||||||
|
| a | d | road,road | depart,arrive | [(),(tunnel),()],[()] |
|
||||||
|
|
||||||
|
Scenario: Bicycle - From roundabout on ferry
|
||||||
|
Given the node map
|
||||||
|
"""
|
||||||
|
c
|
||||||
|
/ \
|
||||||
|
a---b d---f--h
|
||||||
|
\ /
|
||||||
|
e
|
||||||
|
|
|
||||||
|
g
|
||||||
|
"""
|
||||||
|
|
||||||
|
And the ways
|
||||||
|
| nodes | oneway | highway | junction | route |
|
||||||
|
| ab | yes | service | | |
|
||||||
|
| cb | yes | service | roundabout | |
|
||||||
|
| dc | yes | service | roundabout | |
|
||||||
|
| be | yes | service | roundabout | |
|
||||||
|
| ed | yes | service | roundabout | |
|
||||||
|
| eg | yes | service | | |
|
||||||
|
| df | | | | ferry |
|
||||||
|
| fh | yes | service | | |
|
||||||
|
|
||||||
|
When I route I should get
|
||||||
|
| from | to | route | turns | classes |
|
||||||
|
| a | h | ab,df,df,fh,fh | depart,roundabout-exit-2,exit roundabout slight right,notification straight,arrive | [()],[(),()],[(ferry)],[()],[()] |
|
||||||
@@ -0,0 +1,55 @@
|
|||||||
|
@routing @bicycle @exclude
|
||||||
|
Feature: Bicycle - Exclude flags
|
||||||
|
Background:
|
||||||
|
Given the profile file "bicycle" initialized with
|
||||||
|
"""
|
||||||
|
profile.excludable = Sequence { Set { 'ferry' } }
|
||||||
|
"""
|
||||||
|
Given the node map
|
||||||
|
"""
|
||||||
|
a....b~~~~~c...f
|
||||||
|
: :
|
||||||
|
d.....e
|
||||||
|
"""
|
||||||
|
|
||||||
|
And the ways
|
||||||
|
| nodes | highway | route | duration | # |
|
||||||
|
| ab | service | | | always drivable |
|
||||||
|
| bc | | ferry | 00:00:01 | not drivable for exclude=ferry, but fast. |
|
||||||
|
| bd | service | | | always drivable |
|
||||||
|
| de | service | | | always drivable |
|
||||||
|
| ec | service | | | always drivable |
|
||||||
|
| cf | service | | | always drivable |
|
||||||
|
|
||||||
|
Scenario: Bicycle - exclude nothing
|
||||||
|
When I route I should get
|
||||||
|
| from | to | route |
|
||||||
|
| a | f | ab,bc,cf,cf |
|
||||||
|
|
||||||
|
When I match I should get
|
||||||
|
| trace | matchings | duration |
|
||||||
|
| abcf | abcf | 109 |
|
||||||
|
|
||||||
|
When I request a travel time matrix I should get
|
||||||
|
| | a | f |
|
||||||
|
| a | 0 | 109 |
|
||||||
|
| f | 109 | 0 |
|
||||||
|
|
||||||
|
Scenario: Bicycle - exclude ferry
|
||||||
|
Given the query options
|
||||||
|
| exclude | ferry |
|
||||||
|
|
||||||
|
When I route I should get
|
||||||
|
| from | to | route |
|
||||||
|
| a | f | ab,bd,de,ec,cf,cf |
|
||||||
|
|
||||||
|
When I match I should get
|
||||||
|
| trace | matchings | duration |
|
||||||
|
| abcf | abcf | 301.2 |
|
||||||
|
|
||||||
|
When I request a travel time matrix I should get
|
||||||
|
| | a | f |
|
||||||
|
| a | 0 | 301 +- 1 |
|
||||||
|
| f | 301.2 +- 1 | 0 |
|
||||||
|
|
||||||
|
|
||||||
@@ -11,11 +11,11 @@ Feature: Bicycle - Adds penalties to unsafe roads
|
|||||||
Then routability should be
|
Then routability should be
|
||||||
| highway | cycleway | forw | backw | forw_rate | backw_rate |
|
| highway | cycleway | forw | backw | forw_rate | backw_rate |
|
||||||
| motorway | | | | | |
|
| motorway | | | | | |
|
||||||
| primary | | 15 km/h | 15 km/h | 2.9 | 2.9 |
|
| primary | | 15 km/h | 15 km/h | 2.1 | 2.1 |
|
||||||
| secondary | | 15 km/h | 15 km/h | 3.1 | 3.1 |
|
| secondary | | 15 km/h | 15 km/h | 2.7 | 2.7 |
|
||||||
| tertiary | | 15 km/h | 15 km/h | 3.3 | 3.3 |
|
| tertiary | | 15 km/h | 15 km/h | 3.3 | 3.3 |
|
||||||
| primary_link | | 15 km/h | 15 km/h | 2.9 | 2.9 |
|
| primary_link | | 15 km/h | 15 km/h | 2.1 | 2.1 |
|
||||||
| secondary_link | | 15 km/h | 15 km/h | 3.1 | 3.1 |
|
| secondary_link | | 15 km/h | 15 km/h | 2.7 | 2.7 |
|
||||||
| tertiary_link | | 15 km/h | 15 km/h | 3.3 | 3.3 |
|
| tertiary_link | | 15 km/h | 15 km/h | 3.3 | 3.3 |
|
||||||
| residential | | 15 km/h | 15 km/h | 4.2 | 4.2 |
|
| residential | | 15 km/h | 15 km/h | 4.2 | 4.2 |
|
||||||
| cycleway | | 15 km/h | 15 km/h | 4.2 | 4.2 |
|
| cycleway | | 15 km/h | 15 km/h | 4.2 | 4.2 |
|
||||||
@@ -51,49 +51,49 @@ Feature: Bicycle - Adds penalties to unsafe roads
|
|||||||
Then routability should be
|
Then routability should be
|
||||||
| highway | cycleway:right | cycleway:left | forw | backw | forw_rate | backw_rate |
|
| highway | cycleway:right | cycleway:left | forw | backw | forw_rate | backw_rate |
|
||||||
| motorway | track | | 15 km/h | | 4.2 | |
|
| motorway | track | | 15 km/h | | 4.2 | |
|
||||||
| primary | track | | 15 km/h | 15 km/h | 4.2 | 2.9 |
|
| primary | track | | 15 km/h | 15 km/h | 4.2 | 2.1 |
|
||||||
| secondary | track | | 15 km/h | 15 km/h | 4.2 | 3.1 |
|
| secondary | track | | 15 km/h | 15 km/h | 4.2 | 2.7 |
|
||||||
| tertiary | track | | 15 km/h | 15 km/h | 4.2 | 3.3 |
|
| tertiary | track | | 15 km/h | 15 km/h | 4.2 | 3.3 |
|
||||||
| primary_link | track | | 15 km/h | 15 km/h | 4.2 | 2.9 |
|
| primary_link | track | | 15 km/h | 15 km/h | 4.2 | 2.1 |
|
||||||
| secondary_link | track | | 15 km/h | 15 km/h | 4.2 | 3.1 |
|
| secondary_link | track | | 15 km/h | 15 km/h | 4.2 | 2.7 |
|
||||||
| tertiary_link | track | | 15 km/h | 15 km/h | 4.2 | 3.3 |
|
| tertiary_link | track | | 15 km/h | 15 km/h | 4.2 | 3.3 |
|
||||||
| residential | track | | 15 km/h | 15 km/h | 4.2 | 4.2 |
|
| residential | track | | 15 km/h | 15 km/h | 4.2 | 4.2 |
|
||||||
| cycleway | track | | 15 km/h | 15 km/h | 4.2 | 4.2 |
|
| cycleway | track | | 15 km/h | 15 km/h | 4.2 | 4.2 |
|
||||||
| footway | track | | 15 km/h | 4 km/h +-1 | 4.2 | 1.1 |
|
| footway | track | | 15 km/h | 4 km/h +-1 | 4.2 | 1.1 |
|
||||||
| motorway | | track | 15 km/h | | 4.2 | |
|
| motorway | | track | 15 km/h | | 4.2 | |
|
||||||
| primary | | track | 15 km/h | 15 km/h | 2.9 | 4.2 |
|
| primary | | track | 15 km/h | 15 km/h | 2.1 | 4.2 |
|
||||||
| secondary | | track | 15 km/h | 15 km/h | 3.1 | 4.2 |
|
| secondary | | track | 15 km/h | 15 km/h | 2.7 | 4.2 |
|
||||||
| tertiary | | track | 15 km/h | 15 km/h | 3.3 | 4.2 |
|
| tertiary | | track | 15 km/h | 15 km/h | 3.3 | 4.2 |
|
||||||
| primary_link | | track | 15 km/h | 15 km/h | 2.9 | 4.2 |
|
| primary_link | | track | 15 km/h | 15 km/h | 2.1 | 4.2 |
|
||||||
| secondary_link | | track | 15 km/h | 15 km/h | 3.1 | 4.2 |
|
| secondary_link | | track | 15 km/h | 15 km/h | 2.7 | 4.2 |
|
||||||
| tertiary_link | | track | 15 km/h | 15 km/h | 3.3 | 4.2 |
|
| tertiary_link | | track | 15 km/h | 15 km/h | 3.3 | 4.2 |
|
||||||
| residential | | track | 15 km/h | 15 km/h | 4.2 | 4.2 |
|
| residential | | track | 15 km/h | 15 km/h | 4.2 | 4.2 |
|
||||||
| cycleway | | track | 15 km/h | 15 km/h | 4.2 | 4.2 |
|
| cycleway | | track | 15 km/h | 15 km/h | 4.2 | 4.2 |
|
||||||
| footway | | track | 4 km/h +-1 | 15 km/h | 1.1 | 4.2 |
|
| footway | | track | 4 km/h +-1 | 15 km/h | 1.1 | 4.2 |
|
||||||
| motorway | lane | | 15 km/h | | 4.2 | |
|
| motorway | lane | | 15 km/h | | 4.2 | |
|
||||||
| primary | lane | | 15 km/h | 15 km/h | 4.2 | 2.9 |
|
| primary | lane | | 15 km/h | 15 km/h | 4.2 | 2.1 |
|
||||||
| secondary | lane | | 15 km/h | 15 km/h | 4.2 | 3.1 |
|
| secondary | lane | | 15 km/h | 15 km/h | 4.2 | 2.7 |
|
||||||
| tertiary | lane | | 15 km/h | 15 km/h | 4.2 | 3.3 |
|
| tertiary | lane | | 15 km/h | 15 km/h | 4.2 | 3.3 |
|
||||||
| primary_link | lane | | 15 km/h | 15 km/h | 4.2 | 2.9 |
|
| primary_link | lane | | 15 km/h | 15 km/h | 4.2 | 2.1 |
|
||||||
| secondary_link | lane | | 15 km/h | 15 km/h | 4.2 | 3.1 |
|
| secondary_link | lane | | 15 km/h | 15 km/h | 4.2 | 2.7 |
|
||||||
| tertiary_link | lane | | 15 km/h | 15 km/h | 4.2 | 3.3 |
|
| tertiary_link | lane | | 15 km/h | 15 km/h | 4.2 | 3.3 |
|
||||||
| residential | lane | | 15 km/h +-1 | 15 km/h +-1 | 4.2 | 4.2 |
|
| residential | lane | | 15 km/h +-1 | 15 km/h +-1 | 4.2 | 4.2 |
|
||||||
| cycleway | lane | | 15 km/h | 15 km/h | 4.2 | 4.2 |
|
| cycleway | lane | | 15 km/h | 15 km/h | 4.2 | 4.2 |
|
||||||
| footway | lane | | 15 km/h | 4 km/h +-1 | 4.2 | 1.1 |
|
| footway | lane | | 15 km/h | 4 km/h +-1 | 4.2 | 1.1 |
|
||||||
| motorway | | lane | 15 km/h | | 4.2 | |
|
| motorway | | lane | 15 km/h | | 4.2 | |
|
||||||
| primary | | lane | 15 km/h | 15 km/h | 2.9 | 4.2 |
|
| primary | | lane | 15 km/h | 15 km/h | 2.1 | 4.2 |
|
||||||
| secondary | | lane | 15 km/h +-1 | 15 km/h +-1 | 3.1 | 4.2 |
|
| secondary | | lane | 15 km/h +-1 | 15 km/h +-1 | 2.7 | 4.2 |
|
||||||
| tertiary | | lane | 15 km/h | 15 km/h | 3.3 | 4.2 |
|
| tertiary | | lane | 15 km/h | 15 km/h | 3.3 | 4.2 |
|
||||||
| primary_link | | lane | 15 km/h | 15 km/h | 2.9 | 4.2 |
|
| primary_link | | lane | 15 km/h | 15 km/h | 2.1 | 4.2 |
|
||||||
| secondary_link | | lane | 15 km/h | 15 km/h | 3.1 | 4.2 |
|
| secondary_link | | lane | 15 km/h | 15 km/h | 2.7 | 4.2 |
|
||||||
| tertiary_link | | lane | 15 km/h | 15 km/h | 3.3 | 4.2 |
|
| tertiary_link | | lane | 15 km/h | 15 km/h | 3.3 | 4.2 |
|
||||||
| residential | | lane | 15 km/h | 15 km/h | 4.2 | 4.2 |
|
| residential | | lane | 15 km/h | 15 km/h | 4.2 | 4.2 |
|
||||||
| cycleway | | lane | 15 km/h | 15 km/h | 4.2 | 4.2 |
|
| cycleway | | lane | 15 km/h | 15 km/h | 4.2 | 4.2 |
|
||||||
| footway | | lane | 4 km/h +-1 | 15 km/h | 1.1 | 4.2 |
|
| footway | | lane | 4 km/h +-1 | 15 km/h | 1.1 | 4.2 |
|
||||||
| motorway | shared_lane | | 15 km/h | | 4.2 | |
|
| motorway | shared_lane | | 15 km/h | | 4.2 | |
|
||||||
| primary | shared_lane | | 15 km/h | 15 km/h | 4.2 | 2.9 |
|
| primary | shared_lane | | 15 km/h | 15 km/h | 4.2 | 2.1 |
|
||||||
| motorway | | shared_lane | 15 km/h | | 4.2 | |
|
| motorway | | shared_lane | 15 km/h | | 4.2 | |
|
||||||
| primary | | shared_lane | 15 km/h | 15 km/h | 2.9 | 4.2 |
|
| primary | | shared_lane | 15 km/h | 15 km/h | 2.1 | 4.2 |
|
||||||
|
|
||||||
|
|
||||||
Scenario: Bike - Don't apply penalties for all kind of cycleways
|
Scenario: Bike - Don't apply penalties for all kind of cycleways
|
||||||
|
|||||||
@@ -48,3 +48,22 @@ Feature: Car - Handle physical limitation
|
|||||||
| primary | | none | x |
|
| primary | | none | x |
|
||||||
| primary | | no-sign | x |
|
| primary | | no-sign | x |
|
||||||
| primary | | unsigned | x |
|
| primary | | unsigned | x |
|
||||||
|
|
||||||
|
Scenario: Car - Limited by length
|
||||||
|
Then routability should be
|
||||||
|
| highway | maxlength | bothw |
|
||||||
|
| primary | | x |
|
||||||
|
| primary | 1 | |
|
||||||
|
| primary | 5 | x |
|
||||||
|
| primary | unsigned | x |
|
||||||
|
|
||||||
|
Scenario: Car - Limited by weight
|
||||||
|
Then routability should be
|
||||||
|
| highway | maxweight | bothw |
|
||||||
|
| primary | | x |
|
||||||
|
| primary | 1 | |
|
||||||
|
| primary | 3.5 | x |
|
||||||
|
| primary | 35000 kg | x |
|
||||||
|
| primary | 8.9t | x |
|
||||||
|
| primary | 0.1 lbs | |
|
||||||
|
| primary | unsigned | x |
|
||||||
|
|||||||
@@ -19,7 +19,7 @@ Feature: Barriers
|
|||||||
| entrance | x |
|
| entrance | x |
|
||||||
| wall | |
|
| wall | |
|
||||||
| fence | |
|
| fence | |
|
||||||
| some_tag | |
|
| some_tag | x |
|
||||||
| block | x |
|
| block | x |
|
||||||
|
|
||||||
Scenario: Foot - Access tag trumphs barriers
|
Scenario: Foot - Access tag trumphs barriers
|
||||||
|
|||||||
@@ -1209,3 +1209,33 @@ Feature: Simple Turns
|
|||||||
| a | c | knob,knob | depart,arrive |
|
| a | c | knob,knob | depart,arrive |
|
||||||
| d | e | soph,soph | depart,arrive |
|
| d | e | soph,soph | depart,arrive |
|
||||||
| d | a | soph,knob,knob | depart,turn left,arrive |
|
| d | a | soph,knob,knob | depart,turn left,arrive |
|
||||||
|
|
||||||
|
|
||||||
|
# https://www.openstreetmap.org/node/30797565
|
||||||
|
Scenario: No turn instruction when turning from unnamed onto unnamed
|
||||||
|
Given the node map
|
||||||
|
"""
|
||||||
|
a
|
||||||
|
|
|
||||||
|
|
|
||||||
|
|
|
||||||
|
|
|
||||||
|
b----------------c
|
||||||
|
|
|
||||||
|
|
|
||||||
|
|
|
||||||
|
|
|
||||||
|
|
|
||||||
|
|
|
||||||
|
d
|
||||||
|
"""
|
||||||
|
|
||||||
|
And the ways
|
||||||
|
| nodes | highway | name | ref |
|
||||||
|
| ab | trunk_link | | |
|
||||||
|
| db | secondary | | L 460 |
|
||||||
|
| bc | secondary | | |
|
||||||
|
|
||||||
|
When I route I should get
|
||||||
|
| from | to | route | turns |
|
||||||
|
| d | c | ,, | depart,turn right,arrive |
|
||||||
|
|||||||
@@ -1,74 +1,88 @@
|
|||||||
var util = require('util');
|
var util = require('util');
|
||||||
|
|
||||||
module.exports = function () {
|
module.exports = function () {
|
||||||
this.When(/^I request a travel time matrix I should get$/, (table, callback) => {
|
const durationsRegex = new RegExp(/^I request a travel time matrix I should get$/);
|
||||||
var NO_ROUTE = 2147483647; // MAX_INT
|
const distancesRegex = new RegExp(/^I request a travel distance matrix I should get$/);
|
||||||
|
|
||||||
var tableRows = table.raw();
|
const DURATIONS_NO_ROUTE = 2147483647; // MAX_INT
|
||||||
|
const DISTANCES_NO_ROUTE = 3.40282e+38; // MAX_FLOAT
|
||||||
|
|
||||||
if (tableRows[0][0] !== '') throw new Error('*** Top-left cell of matrix table must be empty');
|
this.When(durationsRegex, function(table, callback) {tableParse.call(this, table, DURATIONS_NO_ROUTE, 'durations', callback);}.bind(this));
|
||||||
|
this.When(distancesRegex, function(table, callback) {tableParse.call(this, table, DISTANCES_NO_ROUTE, 'distances', callback);}.bind(this));
|
||||||
|
};
|
||||||
|
|
||||||
var waypoints = [],
|
const durationsParse = function(v) { return isNaN(parseInt(v)); };
|
||||||
columnHeaders = tableRows[0].slice(1),
|
const distancesParse = function(v) { return isNaN(parseFloat(v)); };
|
||||||
rowHeaders = tableRows.map((h) => h[0]).slice(1),
|
|
||||||
symmetric = columnHeaders.length == rowHeaders.length && columnHeaders.every((ele, i) => ele === rowHeaders[i]);
|
|
||||||
|
|
||||||
if (symmetric) {
|
function tableParse(table, noRoute, annotation, callback) {
|
||||||
columnHeaders.forEach((nodeName) => {
|
|
||||||
var node = this.findNodeByName(nodeName);
|
const parse = annotation == 'distances' ? distancesParse : durationsParse;
|
||||||
if (!node) throw new Error(util.format('*** unknown node "%s"', nodeName));
|
const params = this.queryParams;
|
||||||
waypoints.push({ coord: node, type: 'loc' });
|
params.annotations = annotation == 'distances' ? 'distance' : 'duration';
|
||||||
|
|
||||||
|
var tableRows = table.raw();
|
||||||
|
|
||||||
|
if (tableRows[0][0] !== '') throw new Error('*** Top-left cell of matrix table must be empty');
|
||||||
|
|
||||||
|
var waypoints = [],
|
||||||
|
columnHeaders = tableRows[0].slice(1),
|
||||||
|
rowHeaders = tableRows.map((h) => h[0]).slice(1),
|
||||||
|
symmetric = columnHeaders.length == rowHeaders.length && columnHeaders.every((ele, i) => ele === rowHeaders[i]);
|
||||||
|
|
||||||
|
if (symmetric) {
|
||||||
|
columnHeaders.forEach((nodeName) => {
|
||||||
|
var node = this.findNodeByName(nodeName);
|
||||||
|
if (!node) throw new Error(util.format('*** unknown node "%s"', nodeName));
|
||||||
|
waypoints.push({ coord: node, type: 'loc' });
|
||||||
|
});
|
||||||
|
} else {
|
||||||
|
columnHeaders.forEach((nodeName) => {
|
||||||
|
var node = this.findNodeByName(nodeName);
|
||||||
|
if (!node) throw new Error(util.format('*** unknown node "%s"', nodeName));
|
||||||
|
waypoints.push({ coord: node, type: 'dst' });
|
||||||
|
});
|
||||||
|
rowHeaders.forEach((nodeName) => {
|
||||||
|
var node = this.findNodeByName(nodeName);
|
||||||
|
if (!node) throw new Error(util.format('*** unknown node "%s"', nodeName));
|
||||||
|
waypoints.push({ coord: node, type: 'src' });
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
var actual = [];
|
||||||
|
actual.push(table.headers);
|
||||||
|
|
||||||
|
this.reprocessAndLoadData((e) => {
|
||||||
|
if (e) return callback(e);
|
||||||
|
// compute matrix
|
||||||
|
|
||||||
|
this.requestTable(waypoints, params, (err, response) => {
|
||||||
|
if (err) return callback(err);
|
||||||
|
if (!response.body.length) return callback(new Error('Invalid response body'));
|
||||||
|
|
||||||
|
var json = JSON.parse(response.body);
|
||||||
|
|
||||||
|
var result = json[annotation].map(row => {
|
||||||
|
var hashes = {};
|
||||||
|
row.forEach((v, i) => { hashes[tableRows[0][i+1]] = parse(v) ? '' : v; });
|
||||||
|
return hashes;
|
||||||
});
|
});
|
||||||
} else {
|
|
||||||
columnHeaders.forEach((nodeName) => {
|
|
||||||
var node = this.findNodeByName(nodeName);
|
|
||||||
if (!node) throw new Error(util.format('*** unknown node "%s"', nodeName));
|
|
||||||
waypoints.push({ coord: node, type: 'dst' });
|
|
||||||
});
|
|
||||||
rowHeaders.forEach((nodeName) => {
|
|
||||||
var node = this.findNodeByName(nodeName);
|
|
||||||
if (!node) throw new Error(util.format('*** unknown node "%s"', nodeName));
|
|
||||||
waypoints.push({ coord: node, type: 'src' });
|
|
||||||
});
|
|
||||||
}
|
|
||||||
|
|
||||||
var actual = [];
|
var testRow = (row, ri, cb) => {
|
||||||
actual.push(table.headers);
|
for (var k in result[ri]) {
|
||||||
|
if (this.FuzzyMatch.match(result[ri][k], row[k])) {
|
||||||
this.reprocessAndLoadData((e) => {
|
result[ri][k] = row[k];
|
||||||
if (e) return callback(e);
|
} else if (row[k] === '' && result[ri][k] === noRoute) {
|
||||||
// compute matrix
|
result[ri][k] = '';
|
||||||
var params = this.queryParams;
|
} else {
|
||||||
|
result[ri][k] = result[ri][k].toString();
|
||||||
this.requestTable(waypoints, params, (err, response) => {
|
|
||||||
if (err) return callback(err);
|
|
||||||
if (!response.body.length) return callback(new Error('Invalid response body'));
|
|
||||||
|
|
||||||
var json = JSON.parse(response.body);
|
|
||||||
|
|
||||||
var result = json['durations'].map(row => {
|
|
||||||
var hashes = {};
|
|
||||||
row.forEach((v, i) => { hashes[tableRows[0][i+1]] = isNaN(parseInt(v)) ? '' : v; });
|
|
||||||
return hashes;
|
|
||||||
});
|
|
||||||
|
|
||||||
var testRow = (row, ri, cb) => {
|
|
||||||
for (var k in result[ri]) {
|
|
||||||
if (this.FuzzyMatch.match(result[ri][k], row[k])) {
|
|
||||||
result[ri][k] = row[k];
|
|
||||||
} else if (row[k] === '' && result[ri][k] === NO_ROUTE) {
|
|
||||||
result[ri][k] = '';
|
|
||||||
} else {
|
|
||||||
result[ri][k] = result[ri][k].toString();
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|
||||||
result[ri][''] = row[''];
|
result[ri][''] = row[''];
|
||||||
cb(null, result[ri]);
|
cb(null, result[ri]);
|
||||||
};
|
};
|
||||||
|
|
||||||
this.processRowsAndDiff(table, testRow, callback);
|
this.processRowsAndDiff(table, testRow, callback);
|
||||||
});
|
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
};
|
}
|
||||||
|
|||||||
@@ -21,7 +21,8 @@ module.exports = {
|
|||||||
matchRe = want.match(/^\/(.*)\/$/),
|
matchRe = want.match(/^\/(.*)\/$/),
|
||||||
// we use this for matching before/after bearing
|
// we use this for matching before/after bearing
|
||||||
matchBearingListAbs = want.match(/^((\d+)->(\d+))(,(\d+)->(\d+))*\s+\+\-(.+)$/),
|
matchBearingListAbs = want.match(/^((\d+)->(\d+))(,(\d+)->(\d+))*\s+\+\-(.+)$/),
|
||||||
matchIntersectionListAbs = want.match(/^(((((true|false):\d+)\s{0,1})+,{0,1})+;{0,1})+\s+\+\-(.+)$/);
|
matchIntersectionListAbs = want.match(/^(((((true|false):\d+)\s{0,1})+,{0,1})+;{0,1})+\s+\+\-(.+)$/),
|
||||||
|
matchRangeNumbers = want.match(/\d+\+\-\d+/);
|
||||||
|
|
||||||
function inRange(margin, got, want) {
|
function inRange(margin, got, want) {
|
||||||
var fromR = parseFloat(want) - margin,
|
var fromR = parseFloat(want) - margin,
|
||||||
@@ -105,6 +106,11 @@ module.exports = {
|
|||||||
return inRange(margin, got, matchAbs[1]);
|
return inRange(margin, got, matchAbs[1]);
|
||||||
} else if (matchRe) { // regex: /a,b,.*/
|
} else if (matchRe) { // regex: /a,b,.*/
|
||||||
return got.match(matchRe[1]);
|
return got.match(matchRe[1]);
|
||||||
|
} else if (matchRangeNumbers) {
|
||||||
|
let real_want_and_margin = want.split('+-'),
|
||||||
|
margin = parseFloat(real_want_and_margin[1].trim()),
|
||||||
|
real_want = parseFloat(real_want_and_margin[0].trim());
|
||||||
|
return inRange(margin, got, real_want);
|
||||||
} else {
|
} else {
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -51,7 +51,7 @@ module.exports = function () {
|
|||||||
.defer(rimraf, this.scenarioLogFile)
|
.defer(rimraf, this.scenarioLogFile)
|
||||||
.awaitAll(callback);
|
.awaitAll(callback);
|
||||||
// uncomment to get path to logfile
|
// uncomment to get path to logfile
|
||||||
// console.log(" Writing logging output to " + this.scenarioLogFile)
|
// console.log(' Writing logging output to ' + this.scenarioLogFile);
|
||||||
});
|
});
|
||||||
|
|
||||||
this.After((scenario, callback) => {
|
this.After((scenario, callback) => {
|
||||||
|
|||||||
@@ -226,3 +226,22 @@ Feature: Distance calculation
|
|||||||
| x | v | xv,xv | 424m +-1 |
|
| x | v | xv,xv | 424m +-1 |
|
||||||
| x | w | xw,xw | 360m +-1 |
|
| x | w | xw,xw | 360m +-1 |
|
||||||
| x | y | xy,xy | 316m +-1 |
|
| x | y | xy,xy | 316m +-1 |
|
||||||
|
|
||||||
|
|
||||||
|
# Check rounding errors
|
||||||
|
Scenario: Distances Long distances
|
||||||
|
Given a grid size of 1000 meters
|
||||||
|
Given the node map
|
||||||
|
"""
|
||||||
|
a b c d
|
||||||
|
"""
|
||||||
|
|
||||||
|
And the ways
|
||||||
|
| nodes |
|
||||||
|
| abcd |
|
||||||
|
|
||||||
|
When I route I should get
|
||||||
|
| from | to | distance |
|
||||||
|
| a | b | 1000m +-3 |
|
||||||
|
| a | c | 2000m +-3 |
|
||||||
|
| a | d | 3000m +-3 |
|
||||||
|
|||||||
@@ -1,14 +1,12 @@
|
|||||||
@matrix @testbot
|
@matrix @testbot
|
||||||
Feature: Basic Distance Matrix
|
Feature: Basic Distance Matrix
|
||||||
# note that results are travel time, specified in 1/10th of seconds
|
# note that results of travel distance are in metres
|
||||||
# since testbot uses a default speed of 100m/10s, the result matches
|
|
||||||
# the number of meters as long as the way type is the default 'primary'
|
|
||||||
|
|
||||||
Background:
|
Background:
|
||||||
Given the profile "testbot"
|
Given the profile "testbot"
|
||||||
And the partition extra arguments "--small-component-size 1 --max-cell-sizes 2,4,8,16"
|
And the partition extra arguments "--small-component-size 1 --max-cell-sizes 2,4,8,16"
|
||||||
|
|
||||||
Scenario: Testbot - Travel time matrix of minimal network
|
Scenario: Testbot - Travel distance matrix of minimal network
|
||||||
Given the node map
|
Given the node map
|
||||||
"""
|
"""
|
||||||
a b
|
a b
|
||||||
@@ -18,12 +16,99 @@ Feature: Basic Distance Matrix
|
|||||||
| nodes |
|
| nodes |
|
||||||
| ab |
|
| ab |
|
||||||
|
|
||||||
When I request a travel time matrix I should get
|
When I request a travel distance matrix I should get
|
||||||
| | a | b |
|
| | a | b |
|
||||||
| a | 0 | 10 |
|
| a | 0 | 100+-1 |
|
||||||
| b | 10 | 0 |
|
| b | 100+-1 | 0 |
|
||||||
|
|
||||||
Scenario: Testbot - Travel time matrix with different way speeds
|
Scenario: Testbot - Travel distance matrix of minimal network with toll exclude
|
||||||
|
Given the query options
|
||||||
|
| exclude | toll |
|
||||||
|
|
||||||
|
Given the node map
|
||||||
|
"""
|
||||||
|
a b
|
||||||
|
c d
|
||||||
|
"""
|
||||||
|
|
||||||
|
And the ways
|
||||||
|
| nodes | highway | toll | # |
|
||||||
|
| ab | motorway | | not drivable for exclude=motorway |
|
||||||
|
| cd | primary | | always drivable |
|
||||||
|
| ac | primary | yes | not drivable for exclude=toll and exclude=motorway,toll |
|
||||||
|
| bd | motorway | yes | not drivable for exclude=toll and exclude=motorway,toll |
|
||||||
|
|
||||||
|
When I request a travel distance matrix I should get
|
||||||
|
| | a | b | c | d |
|
||||||
|
| a | 0 | 100+-1 | | |
|
||||||
|
| b | 100+-1 | 0 | | |
|
||||||
|
| c | | | 0 | 100+-1 |
|
||||||
|
| d | | | 100+-1 | 0 |
|
||||||
|
|
||||||
|
Scenario: Testbot - Travel distance matrix of minimal network with motorway exclude
|
||||||
|
Given the query options
|
||||||
|
| exclude | motorway |
|
||||||
|
|
||||||
|
Given the node map
|
||||||
|
"""
|
||||||
|
a b
|
||||||
|
c d
|
||||||
|
"""
|
||||||
|
|
||||||
|
And the ways
|
||||||
|
| nodes | highway | # |
|
||||||
|
| ab | motorway | not drivable for exclude=motorway |
|
||||||
|
| cd | residential | |
|
||||||
|
| ac | residential | |
|
||||||
|
| bd | residential | |
|
||||||
|
|
||||||
|
When I request a travel distance matrix I should get
|
||||||
|
| | a | b | c | d |
|
||||||
|
| a | 0 | 300+-2 | 100+-2 | 200+-2 |
|
||||||
|
|
||||||
|
Scenario: Testbot - Travel distance matrix of minimal network disconnected motorway exclude
|
||||||
|
Given the query options
|
||||||
|
| exclude | motorway |
|
||||||
|
And the extract extra arguments "--small-component-size 4"
|
||||||
|
|
||||||
|
Given the node map
|
||||||
|
"""
|
||||||
|
ab efgh
|
||||||
|
cd
|
||||||
|
"""
|
||||||
|
|
||||||
|
And the ways
|
||||||
|
| nodes | highway | # |
|
||||||
|
| be | motorway | not drivable for exclude=motorway |
|
||||||
|
| abcd | residential | |
|
||||||
|
| efgh | residential | |
|
||||||
|
|
||||||
|
When I request a travel distance matrix I should get
|
||||||
|
| | a | b | e |
|
||||||
|
| a | 0 | 50+-1 | |
|
||||||
|
|
||||||
|
Scenario: Testbot - Travel distance matrix of minimal network with motorway and toll excludes
|
||||||
|
Given the query options
|
||||||
|
| exclude | motorway,toll |
|
||||||
|
|
||||||
|
Given the node map
|
||||||
|
"""
|
||||||
|
a b e f
|
||||||
|
c d g h
|
||||||
|
"""
|
||||||
|
|
||||||
|
And the ways
|
||||||
|
| nodes | highway | toll | # |
|
||||||
|
| be | motorway | | not drivable for exclude=motorway |
|
||||||
|
| dg | primary | yes | not drivable for exclude=toll |
|
||||||
|
| abcd | residential | | |
|
||||||
|
| efgh | residential | | |
|
||||||
|
|
||||||
|
When I request a travel distance matrix I should get
|
||||||
|
| | a | b | e | g |
|
||||||
|
| a | 0 | 100+-1 | | |
|
||||||
|
|
||||||
|
Scenario: Testbot - Travel distance matrix with different way speeds
|
||||||
Given the node map
|
Given the node map
|
||||||
"""
|
"""
|
||||||
a b c d
|
a b c d
|
||||||
@@ -35,40 +120,25 @@ Feature: Basic Distance Matrix
|
|||||||
| bc | secondary |
|
| bc | secondary |
|
||||||
| cd | tertiary |
|
| cd | tertiary |
|
||||||
|
|
||||||
When I request a travel time matrix I should get
|
When I request a travel distance matrix I should get
|
||||||
| | a | b | c | d |
|
| | a | b | c | d |
|
||||||
| a | 0 | 10 | 30 | 60 |
|
| a | 0 | 100+-1 | 200+-1 | 300+-1 |
|
||||||
| b | 10 | 0 | 20 | 50 |
|
| b | 100+-1 | 0 | 100+-1 | 200+-1 |
|
||||||
| c | 30 | 20 | 0 | 30 |
|
| c | 200+-1 | 100+-1 | 0 | 100+-1 |
|
||||||
| d | 60 | 50 | 30 | 0 |
|
| d | 300+-1 | 200+-1 | 100+-1 | 0 |
|
||||||
|
|
||||||
When I request a travel time matrix I should get
|
When I request a travel distance matrix I should get
|
||||||
| | a | b | c | d |
|
| | a | b | c | d |
|
||||||
| a | 0 | 10 | 30 | 60 |
|
| a | 0 | 100+-1 | 200+-1 | 300+-1 |
|
||||||
|
|
||||||
When I request a travel time matrix I should get
|
When I request a travel distance matrix I should get
|
||||||
| | a |
|
| | a |
|
||||||
| a | 0 |
|
| a | 0 |
|
||||||
| b | 10 |
|
| b | 100+-1 |
|
||||||
| c | 30 |
|
| c | 200+-1 |
|
||||||
| d | 60 |
|
| d | 300+-1 |
|
||||||
|
|
||||||
Scenario: Testbot - Travel time matrix with fuzzy match
|
Scenario: Testbot - Travel distance matrix of small grid
|
||||||
Given the node map
|
|
||||||
"""
|
|
||||||
a b
|
|
||||||
"""
|
|
||||||
|
|
||||||
And the ways
|
|
||||||
| nodes |
|
|
||||||
| ab |
|
|
||||||
|
|
||||||
When I request a travel time matrix I should get
|
|
||||||
| | a | b |
|
|
||||||
| a | 0 | 10 |
|
|
||||||
| b | 10 | 0 |
|
|
||||||
|
|
||||||
Scenario: Testbot - Travel time matrix of small grid
|
|
||||||
Given the node map
|
Given the node map
|
||||||
"""
|
"""
|
||||||
a b c
|
a b c
|
||||||
@@ -83,14 +153,14 @@ Feature: Basic Distance Matrix
|
|||||||
| be |
|
| be |
|
||||||
| cf |
|
| cf |
|
||||||
|
|
||||||
When I request a travel time matrix I should get
|
When I request a travel distance matrix I should get
|
||||||
| | a | b | e | f |
|
| | a | b | e | f |
|
||||||
| a | 0 | 10 | 20 | 30 |
|
| a | 0 | 100+-1 | 200+-1 | 300+-1 |
|
||||||
| b | 10 | 0 | 10 | 20 |
|
| b | 100+-1 | 0 | 100+-1 | 200+-1 |
|
||||||
| e | 20 | 10 | 0 | 10 |
|
| e | 200+-1 | 100+-1 | 0 | 100+-1 |
|
||||||
| f | 30 | 20 | 10 | 0 |
|
| f | 300+-1 | 200+-1 | 100+-1 | 0 |
|
||||||
|
|
||||||
Scenario: Testbot - Travel time matrix of network with unroutable parts
|
Scenario: Testbot - Travel distance matrix of network with unroutable parts
|
||||||
Given the node map
|
Given the node map
|
||||||
"""
|
"""
|
||||||
a b
|
a b
|
||||||
@@ -100,12 +170,12 @@ Feature: Basic Distance Matrix
|
|||||||
| nodes | oneway |
|
| nodes | oneway |
|
||||||
| ab | yes |
|
| ab | yes |
|
||||||
|
|
||||||
When I request a travel time matrix I should get
|
When I request a travel distance matrix I should get
|
||||||
| | a | b |
|
| | a | b |
|
||||||
| a | 0 | 10 |
|
| a | 0 | 100+-1 |
|
||||||
| b | | 0 |
|
| b | | 0 |
|
||||||
|
|
||||||
Scenario: Testbot - Travel time matrix of network with oneways
|
Scenario: Testbot - Travel distance matrix of network with oneways
|
||||||
Given the node map
|
Given the node map
|
||||||
"""
|
"""
|
||||||
x a b y
|
x a b y
|
||||||
@@ -118,14 +188,14 @@ Feature: Basic Distance Matrix
|
|||||||
| xa | |
|
| xa | |
|
||||||
| by | |
|
| by | |
|
||||||
|
|
||||||
When I request a travel time matrix I should get
|
When I request a travel distance matrix I should get
|
||||||
| | x | y | d | e |
|
| | x | y | d | e |
|
||||||
| x | 0 | 30 | 40 | 30 |
|
| x | 0 | 300+-2 | 400+-2 | 300+-2 |
|
||||||
| y | 50 | 0 | 30 | 20 |
|
| y | 500+-2 | 0 | 300+-2 | 200+-2 |
|
||||||
| d | 20 | 30 | 0 | 30 |
|
| d | 200+-2 | 300+-2 | 0 | 300+-2 |
|
||||||
| e | 30 | 40 | 10 | 0 |
|
| e | 300+-2 | 400+-2 | 100+-2 | 0 |
|
||||||
|
|
||||||
Scenario: Testbot - Rectangular travel time matrix
|
Scenario: Testbot - Rectangular travel distance matrix
|
||||||
Given the node map
|
Given the node map
|
||||||
"""
|
"""
|
||||||
a b c
|
a b c
|
||||||
@@ -140,51 +210,57 @@ Feature: Basic Distance Matrix
|
|||||||
| be |
|
| be |
|
||||||
| cf |
|
| cf |
|
||||||
|
|
||||||
When I request a travel time matrix I should get
|
When I route I should get
|
||||||
| | a | b | e | f |
|
| from | to | distance |
|
||||||
| a | 0 | 10 | 20 | 30 |
|
| e | a | 200m +- 1 |
|
||||||
|
| e | b | 100m +- 1 |
|
||||||
|
| f | a | 300m +- 1 |
|
||||||
|
| f | b | 200m +- 1 |
|
||||||
|
|
||||||
When I request a travel time matrix I should get
|
When I request a travel distance matrix I should get
|
||||||
| | a |
|
| | a | b | e | f |
|
||||||
| a | 0 |
|
| a | 0 | 100+-1 | 200+-1 | 300+-1 |
|
||||||
| b | 10 |
|
|
||||||
| e | 20 |
|
|
||||||
| f | 30 |
|
|
||||||
|
|
||||||
When I request a travel time matrix I should get
|
When I request a travel distance matrix I should get
|
||||||
| | a | b | e | f |
|
| | a |
|
||||||
| a | 0 | 10 | 20 | 30 |
|
| a | 0 |
|
||||||
| b | 10 | 0 | 10 | 20 |
|
| b | 100+-1 |
|
||||||
|
| e | 200+-1 |
|
||||||
|
| f | 300+-1 |
|
||||||
|
|
||||||
When I request a travel time matrix I should get
|
When I request a travel distance matrix I should get
|
||||||
| | a | b |
|
| | a | b | e | f |
|
||||||
| a | 0 | 10 |
|
| a | 0 | 100+-1 | 200+-1 | 300+-1 |
|
||||||
| b | 10 | 0 |
|
| b | 100+-1 | 0 | 100+-1 | 200+-1 |
|
||||||
| e | 20 | 10 |
|
|
||||||
| f | 30 | 20 |
|
|
||||||
|
|
||||||
When I request a travel time matrix I should get
|
When I request a travel distance matrix I should get
|
||||||
| | a | b | e | f |
|
| | a | b |
|
||||||
| a | 0 | 10 | 20 | 30 |
|
| a | 0 | 100+-1 |
|
||||||
| b | 10 | 0 | 10 | 20 |
|
| b | 100+-1 | 0 |
|
||||||
| e | 20 | 10 | 0 | 10 |
|
| e | 200+-1 | 100+-1 |
|
||||||
|
| f | 300+-1 | 200+-1 |
|
||||||
|
|
||||||
When I request a travel time matrix I should get
|
When I request a travel distance matrix I should get
|
||||||
| | a | b | e |
|
| | a | b | e | f |
|
||||||
| a | 0 | 10 | 20 |
|
| a | 0 | 100+-1 | 200+-1 | 300+-1 |
|
||||||
| b | 10 | 0 | 10 |
|
| b | 100+-1 | 0 | 100+-1 | 200+-1 |
|
||||||
| e | 20 | 10 | 0 |
|
| e | 200+-1 | 100+-1 | 0 | 100+-1 |
|
||||||
| f | 30 | 20 | 10 |
|
|
||||||
|
|
||||||
When I request a travel time matrix I should get
|
When I request a travel distance matrix I should get
|
||||||
| | a | b | e | f |
|
| | a | b | e |
|
||||||
| a | 0 | 10 | 20 | 30 |
|
| a | 0 | 100+-1 | 200+-1 |
|
||||||
| b | 10 | 0 | 10 | 20 |
|
| b | 100+-1 | 0 | 100+-1 |
|
||||||
| e | 20 | 10 | 0 | 10 |
|
| e | 200+-1 | 100+-1 | 0 |
|
||||||
| f | 30 | 20 | 10 | 0 |
|
| f | 300+-1 | 200+-1 | 100+-1 |
|
||||||
|
|
||||||
|
When I request a travel distance matrix I should get
|
||||||
|
| | a | b | e | f |
|
||||||
|
| a | 0 | 100+-1 | 200+-1 | 300+-1 |
|
||||||
|
| b | 100+-1 | 0 | 100+-1 | 200+-1 |
|
||||||
|
| e | 200+-1 | 100+-1 | 0 | 100+-1 |
|
||||||
|
| f | 300+-1 | 200+-1 | 100+-1 | 0 |
|
||||||
|
|
||||||
Scenario: Testbot - Travel time 3x2 matrix
|
Scenario: Testbot - Travel distance 3x2 matrix
|
||||||
Given the node map
|
Given the node map
|
||||||
"""
|
"""
|
||||||
a b c
|
a b c
|
||||||
@@ -199,10 +275,11 @@ Feature: Basic Distance Matrix
|
|||||||
| be |
|
| be |
|
||||||
| cf |
|
| cf |
|
||||||
|
|
||||||
When I request a travel time matrix I should get
|
|
||||||
| | b | e | f |
|
When I request a travel distance matrix I should get
|
||||||
| a | 10 | 20 | 30 |
|
| | b | e | f |
|
||||||
| b | 0 | 10 | 20 |
|
| a | 100+-1 | 200+-1 | 300+-1 |
|
||||||
|
| b | 0 | 100+-1 | 200+-1 |
|
||||||
|
|
||||||
Scenario: Testbot - All coordinates are from same small component
|
Scenario: Testbot - All coordinates are from same small component
|
||||||
Given a grid size of 300 meters
|
Given a grid size of 300 meters
|
||||||
@@ -221,10 +298,10 @@ Feature: Basic Distance Matrix
|
|||||||
| da |
|
| da |
|
||||||
| fg |
|
| fg |
|
||||||
|
|
||||||
When I request a travel time matrix I should get
|
When I request a travel distance matrix I should get
|
||||||
| | f | g |
|
| | f | g |
|
||||||
| f | 0 | 30 |
|
| f | 0 | 300+-2 |
|
||||||
| g | 30 | 0 |
|
| g | 300+-2 | 0 |
|
||||||
|
|
||||||
Scenario: Testbot - Coordinates are from different small component and snap to big CC
|
Scenario: Testbot - Coordinates are from different small component and snap to big CC
|
||||||
Given a grid size of 300 meters
|
Given a grid size of 300 meters
|
||||||
@@ -244,14 +321,25 @@ Feature: Basic Distance Matrix
|
|||||||
| fg |
|
| fg |
|
||||||
| hi |
|
| hi |
|
||||||
|
|
||||||
When I request a travel time matrix I should get
|
When I route I should get
|
||||||
| | f | g | h | i |
|
| from | to | distance |
|
||||||
| f | 0 | 30 | 0 | 30 |
|
| f | g | 300m |
|
||||||
| g | 30 | 0 | 30 | 0 |
|
| f | i | 300m |
|
||||||
| h | 0 | 30 | 0 | 30 |
|
| g | f | 300m |
|
||||||
| i | 30 | 0 | 30 | 0 |
|
| g | h | 300m |
|
||||||
|
| h | g | 300m |
|
||||||
|
| h | i | 300m |
|
||||||
|
| i | f | 300m |
|
||||||
|
| i | h | 300m |
|
||||||
|
|
||||||
Scenario: Testbot - Travel time matrix with loops
|
When I request a travel distance matrix I should get
|
||||||
|
| | f | g | h | i |
|
||||||
|
| f | 0 | 300+-2 | 0 | 300+-2 |
|
||||||
|
| g | 300+-2 | 0 | 300+-2 | 0 |
|
||||||
|
| h | 0 | 300+-2 | 0 | 300+-2 |
|
||||||
|
| i | 300+-2 | 0 | 300+-2 | 0 |
|
||||||
|
|
||||||
|
Scenario: Testbot - Travel distance matrix with loops
|
||||||
Given the node map
|
Given the node map
|
||||||
"""
|
"""
|
||||||
a 1 2 b
|
a 1 2 b
|
||||||
@@ -265,14 +353,15 @@ Feature: Basic Distance Matrix
|
|||||||
| cd | yes |
|
| cd | yes |
|
||||||
| da | yes |
|
| da | yes |
|
||||||
|
|
||||||
When I request a travel time matrix I should get
|
When I request a travel distance matrix I should get
|
||||||
| | 1 | 2 | 3 | 4 |
|
| | 1 | 2 | 3 | 4 |
|
||||||
| 1 | 0 | 10 +-1 | 40 +-1 | 50 +-1 |
|
| 1 | 0 | 100+-1 | 400+-1 | 500+-1 |
|
||||||
| 2 | 70 +-1 | 0 | 30 +-1 | 40 +-1 |
|
| 2 | 700+-1 | 0 | 300+-1 | 400+-1 |
|
||||||
| 3 | 40 +-1 | 50 +-1 | 0 | 10 +-1 |
|
| 3 | 400+-1 | 500+-1 | 0 | 100+-1 |
|
||||||
| 4 | 30 +-1 | 40 +-1 | 70 +-1 | 0 |
|
| 4 | 300+-1 | 400+-1 | 700+-1 | 0 |
|
||||||
|
|
||||||
Scenario: Testbot - Travel time matrix based on segment durations
|
|
||||||
|
Scenario: Testbot - Travel distance matrix based on segment durations
|
||||||
Given the profile file
|
Given the profile file
|
||||||
"""
|
"""
|
||||||
local functions = require('testbot')
|
local functions = require('testbot')
|
||||||
@@ -301,20 +390,19 @@ Feature: Basic Distance Matrix
|
|||||||
"""
|
"""
|
||||||
|
|
||||||
And the ways
|
And the ways
|
||||||
| nodes |
|
| nodes |
|
||||||
| abcd |
|
| abcd |
|
||||||
| ce |
|
| ce |
|
||||||
|
|
||||||
When I request a travel time matrix I should get
|
When I request a travel distance matrix I should get
|
||||||
| | a | b | c | d | e |
|
| | a | b | c | d | e |
|
||||||
| a | 0 | 11 | 22 | 33 | 33 |
|
| a | 0 | 100+-2 | 200+-2 | 300+-2 | 400+-2 |
|
||||||
| b | 11 | 0 | 11 | 22 | 22 |
|
| b | 100+-2 | 0 | 100+-2 | 200+-2 | 300+-2 |
|
||||||
| c | 22 | 11 | 0 | 11 | 11 |
|
| c | 200+-2 | 100+-2 | 0 | 100+-2 | 200+-2 |
|
||||||
| d | 33 | 22 | 11 | 0 | 22 |
|
| d | 300+-2 | 200+-2 | 100+-2 | 0 | 300+-2 |
|
||||||
| e | 33 | 22 | 11 | 22 | 0 |
|
| e | 400+-2 | 300+-2 | 200+-2 | 300+-2 | 0 |
|
||||||
|
|
||||||
|
Scenario: Testbot - Travel distance matrix for alternative loop paths
|
||||||
Scenario: Testbot - Travel time matrix for alternative loop paths
|
|
||||||
Given the profile file
|
Given the profile file
|
||||||
"""
|
"""
|
||||||
local functions = require('testbot')
|
local functions = require('testbot')
|
||||||
@@ -350,62 +438,132 @@ Feature: Basic Distance Matrix
|
|||||||
| dc | yes |
|
| dc | yes |
|
||||||
| ca | yes |
|
| ca | yes |
|
||||||
|
|
||||||
When I request a travel time matrix I should get
|
When I request a travel distance matrix I should get
|
||||||
| | 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 |
|
| | 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 |
|
||||||
| 1 | 0 | 11 | 3 | 2 | 6 | 5 | 8.9 | 7.9 |
|
| 1 | 0 | 1100+-5 | 300+-5 | 200+-5 | 600+-5 | 500+-5 | 900+-5 | 800+-5 |
|
||||||
| 2 | 1 | 0 | 4 | 3 | 7 | 6 | 9.9 | 8.9 |
|
| 2 | 100+-5 | 0 | 400+-5 | 300+-5 | 700+-5 | 600+-5 | 1000+-5 | 900+-5 |
|
||||||
| 3 | 9 | 8 | 0 | 11 | 3 | 2 | 5.9 | 4.9 |
|
| 3 | 900+-5 | 800+-5 | 0 | 1100+-5 | 300+-5 | 200+-5 | 600+-5 | 500+-5 |
|
||||||
| 4 | 10 | 9 | 1 | 0 | 4 | 3 | 6.9 | 5.9 |
|
| 4 | 1000+-5 | 900+-5 | 100+-5 | 0 | 400+-5 | 300+-5 | 700+-5 | 600+-5 |
|
||||||
| 5 | 6 | 5 | 9 | 8 | 0 | 11 | 2.9 | 1.9 |
|
| 5 | 600+-5 | 500+-5 | 900+-5 | 800+-5 | 0 | 1100+-5 | 300+-5 | 200+-5 |
|
||||||
| 6 | 7 | 6 | 10 | 9 | 1 | 0 | 3.9 | 2.9 |
|
| 6 | 700+-5 | 600+-5 | 1000+-5 | 900+-5 | 100+-5 | 0 | 400+-5 | 300+-5 |
|
||||||
| 7 | 3.1 | 2.1 | 6.1 | 5.1 | 9.1 | 8.1 | 0 | 11 |
|
| 7 | 300+-5 | 200+-5 | 600+-5 | 500+-5 | 900+-5 | 800+-5 | 0 | 1100+-5 |
|
||||||
| 8 | 4.1 | 3.1 | 7.1 | 6.1 | 10.1 | 9.1 | 1 | 0 |
|
| 8 | 400+-5 | 300+-5 | 700+-5 | 600+-5 | 1000+-5 | 900+-5 | 100+-5 | 0 |
|
||||||
|
|
||||||
|
When I request a travel distance matrix I should get
|
||||||
|
| | 1 |
|
||||||
|
| 1 | 0 |
|
||||||
|
| 2 | 100+-5 |
|
||||||
|
| 3 | 900+-5 |
|
||||||
|
| 4 | 1000+-5 |
|
||||||
|
| 5 | 600+-5 |
|
||||||
|
| 6 | 700+-5 |
|
||||||
|
| 7 | 300+-5 |
|
||||||
|
| 8 | 400+-5 |
|
||||||
|
|
||||||
Scenario: Testbot - Travel time matrix with ties
|
Scenario: Testbot - Travel distance matrix with ties
|
||||||
Given the profile file
|
Given the node map
|
||||||
"""
|
|
||||||
local functions = require('testbot')
|
|
||||||
functions.process_segment = function(profile, segment)
|
|
||||||
segment.weight = 1
|
|
||||||
segment.duration = 1
|
|
||||||
end
|
|
||||||
functions.process_turn = function(profile, turn)
|
|
||||||
if turn.angle >= 0 then
|
|
||||||
turn.duration = 16
|
|
||||||
else
|
|
||||||
turn.duration = 4
|
|
||||||
end
|
|
||||||
turn.weight = 0
|
|
||||||
end
|
|
||||||
return functions
|
|
||||||
"""
|
|
||||||
And the node map
|
|
||||||
"""
|
"""
|
||||||
a b
|
a b
|
||||||
|
|
||||||
c d
|
c d
|
||||||
"""
|
"""
|
||||||
|
|
||||||
And the ways
|
And the ways
|
||||||
| nodes |
|
| nodes |
|
||||||
| ab |
|
| ab |
|
||||||
| ac |
|
| ac |
|
||||||
| bd |
|
| bd |
|
||||||
| dc |
|
| dc |
|
||||||
|
|
||||||
|
|
||||||
When I route I should get
|
When I route I should get
|
||||||
| from | to | route | distance | time | weight |
|
| from | to | route | distance | time | weight |
|
||||||
| a | c | ac,ac | 200m | 5s | 5 |
|
| a | c | ac,ac | 200m | 20s | 20 |
|
||||||
|
|
||||||
When I request a travel time matrix I should get
|
When I route I should get
|
||||||
| | a | b | c | d |
|
| from | to | route | distance |
|
||||||
| a | 0 | 1 | 5 | 10 |
|
| a | b | ab,ab | 450m |
|
||||||
|
| a | c | ac,ac | 200m |
|
||||||
|
| a | d | ac,dc,dc | 500m +- 1 |
|
||||||
|
|
||||||
When I request a travel time matrix I should get
|
When I request a travel distance matrix I should get
|
||||||
| | a |
|
| | a | b | c | d |
|
||||||
| a | 0 |
|
| a | 0 | 450+-2 | 200+-2 | 500+-2 |
|
||||||
| b | 1 |
|
|
||||||
| c | 15 |
|
When I request a travel distance matrix I should get
|
||||||
| d | 10 |
|
| | a |
|
||||||
|
| a | 0 |
|
||||||
|
| b | 450+-2 |
|
||||||
|
| c | 200+-2 |
|
||||||
|
| d | 500+-2 |
|
||||||
|
|
||||||
|
When I request a travel distance matrix I should get
|
||||||
|
| | a | c |
|
||||||
|
| a | 0 | 200+-2 |
|
||||||
|
| c | 200+-2 | 0 |
|
||||||
|
|
||||||
|
|
||||||
|
# Check rounding errors
|
||||||
|
Scenario: Testbot - Long distances in tables
|
||||||
|
Given a grid size of 1000 meters
|
||||||
|
Given the node map
|
||||||
|
"""
|
||||||
|
a b c d
|
||||||
|
"""
|
||||||
|
|
||||||
|
And the ways
|
||||||
|
| nodes |
|
||||||
|
| abcd |
|
||||||
|
|
||||||
|
When I request a travel distance matrix I should get
|
||||||
|
| | a | b | c | d |
|
||||||
|
| a | 0 | 1000+-3 | 2000+-3 | 3000+-3 |
|
||||||
|
|
||||||
|
|
||||||
|
Scenario: Testbot - OneToMany vs ManyToOne
|
||||||
|
Given the node map
|
||||||
|
"""
|
||||||
|
a b
|
||||||
|
c
|
||||||
|
"""
|
||||||
|
|
||||||
|
And the ways
|
||||||
|
| nodes | oneway |
|
||||||
|
| ab | yes |
|
||||||
|
| ac | |
|
||||||
|
| bc | |
|
||||||
|
|
||||||
|
When I request a travel distance matrix I should get
|
||||||
|
| | a | b |
|
||||||
|
| b | 240.4 | 0 |
|
||||||
|
|
||||||
|
When I request a travel distance matrix I should get
|
||||||
|
| | a |
|
||||||
|
| a | 0 |
|
||||||
|
| b | 240.4 |
|
||||||
|
|
||||||
|
Scenario: Testbot - Varying distances between nodes
|
||||||
|
Given the node map
|
||||||
|
"""
|
||||||
|
a b c d
|
||||||
|
|
||||||
|
e
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
f
|
||||||
|
"""
|
||||||
|
|
||||||
|
And the ways
|
||||||
|
| nodes | oneway |
|
||||||
|
| feabcd | yes |
|
||||||
|
| ec | |
|
||||||
|
| fd | |
|
||||||
|
|
||||||
|
When I request a travel distance matrix I should get
|
||||||
|
| | a | b | c | d | e | f |
|
||||||
|
| a | 0 | 100+-1 | 300+-1 | 650+-1 | 1930+-1 | 1533+-1 |
|
||||||
|
| b | 760+-1 | 0 | 200+-1 | 550+-1 | 1830+-1 | 1433+-1 |
|
||||||
|
| c | 560+-2 | 660+-2 | 0 | 350+-1 | 1630+-1 | 1233+-1 |
|
||||||
|
| d | 1480+-2 | 1580+-1 | 1780+-1 | 0 | 1280+-1 | 883+-1 |
|
||||||
|
| e | 200+-2 | 300+-2 | 500+-1 | 710+-1 | 0 | 1593+-1 |
|
||||||
|
| f | 597+-1 | 696+-1 | 896+-1 | 1108+-1 | 400+-3 | 0 |
|
||||||
|
|||||||
@@ -0,0 +1,512 @@
|
|||||||
|
@matrix @testbot
|
||||||
|
Feature: Basic Duration Matrix
|
||||||
|
# note that results of travel time are in seconds
|
||||||
|
|
||||||
|
Background:
|
||||||
|
Given the profile "testbot"
|
||||||
|
And the partition extra arguments "--small-component-size 1 --max-cell-sizes 2,4,8,16"
|
||||||
|
|
||||||
|
Scenario: Testbot - Travel time matrix of minimal network
|
||||||
|
Given the node map
|
||||||
|
"""
|
||||||
|
a b
|
||||||
|
"""
|
||||||
|
|
||||||
|
And the ways
|
||||||
|
| nodes |
|
||||||
|
| ab |
|
||||||
|
|
||||||
|
When I request a travel time matrix I should get
|
||||||
|
| | a | b |
|
||||||
|
| a | 0 | 10 |
|
||||||
|
| b | 10 | 0 |
|
||||||
|
|
||||||
|
@ch
|
||||||
|
Scenario: Testbot - Travel time matrix of minimal network with toll exclude
|
||||||
|
Given the query options
|
||||||
|
| exclude | toll |
|
||||||
|
|
||||||
|
Given the node map
|
||||||
|
"""
|
||||||
|
a b
|
||||||
|
c d
|
||||||
|
"""
|
||||||
|
|
||||||
|
And the ways
|
||||||
|
| nodes | highway | toll | # |
|
||||||
|
| ab | motorway | | not drivable for exclude=motorway |
|
||||||
|
| cd | primary | | always drivable |
|
||||||
|
| ac | motorway | yes | not drivable for exclude=toll and exclude=motorway,toll |
|
||||||
|
| bd | motorway | yes | not drivable for exclude=toll and exclude=motorway,toll |
|
||||||
|
|
||||||
|
When I request a travel time matrix I should get
|
||||||
|
| | a | b | c | d |
|
||||||
|
| a | 0 | 15 | | |
|
||||||
|
| b | 15 | 0 | | |
|
||||||
|
| c | | | 0 | 10 |
|
||||||
|
| d | | | 10 | 0 |
|
||||||
|
|
||||||
|
@ch
|
||||||
|
Scenario: Testbot - Travel time matrix of minimal network with motorway exclude
|
||||||
|
Given the query options
|
||||||
|
| exclude | motorway |
|
||||||
|
|
||||||
|
Given the node map
|
||||||
|
"""
|
||||||
|
a b
|
||||||
|
c d
|
||||||
|
"""
|
||||||
|
|
||||||
|
And the ways
|
||||||
|
| nodes | highway | # |
|
||||||
|
| ab | motorway | not drivable for exclude=motorway |
|
||||||
|
| cd | residential | |
|
||||||
|
| ac | residential | |
|
||||||
|
| bd | residential | |
|
||||||
|
|
||||||
|
When I request a travel time matrix I should get
|
||||||
|
| | a | b | c | d |
|
||||||
|
| a | 0 | 45 | 15 | 30 |
|
||||||
|
|
||||||
|
@ch
|
||||||
|
Scenario: Testbot - Travel time matrix of minimal network disconnected motorway exclude
|
||||||
|
Given the query options
|
||||||
|
| exclude | motorway |
|
||||||
|
|
||||||
|
Given the node map
|
||||||
|
"""
|
||||||
|
ab efgh
|
||||||
|
cd
|
||||||
|
"""
|
||||||
|
|
||||||
|
And the ways
|
||||||
|
| nodes | highway | # |
|
||||||
|
| be | motorway | not drivable for exclude=motorway |
|
||||||
|
| abcd | residential | |
|
||||||
|
| efgh | residential | |
|
||||||
|
|
||||||
|
When I request a travel time matrix I should get
|
||||||
|
| | a | b | e |
|
||||||
|
| a | 0 | 7.5 | |
|
||||||
|
|
||||||
|
@ch
|
||||||
|
Scenario: Testbot - Travel time matrix of minimal network with motorway and toll excludes
|
||||||
|
Given the query options
|
||||||
|
| exclude | motorway,toll |
|
||||||
|
|
||||||
|
Given the node map
|
||||||
|
"""
|
||||||
|
a b e f
|
||||||
|
c d g h
|
||||||
|
"""
|
||||||
|
|
||||||
|
And the ways
|
||||||
|
| nodes | highway | toll | # |
|
||||||
|
| be | motorway | | not drivable for exclude=motorway |
|
||||||
|
| dg | primary | yes | not drivable for exclude=toll |
|
||||||
|
| abcd | residential | | |
|
||||||
|
| efgh | residential | | |
|
||||||
|
|
||||||
|
When I request a travel time matrix I should get
|
||||||
|
| | a | b | e | g |
|
||||||
|
| a | 0 | 15 | | |
|
||||||
|
|
||||||
|
Scenario: Testbot - Travel time matrix with different way speeds
|
||||||
|
Given the node map
|
||||||
|
"""
|
||||||
|
a b c d
|
||||||
|
"""
|
||||||
|
|
||||||
|
And the ways
|
||||||
|
| nodes | highway |
|
||||||
|
| ab | primary |
|
||||||
|
| bc | secondary |
|
||||||
|
| cd | tertiary |
|
||||||
|
|
||||||
|
When I request a travel time matrix I should get
|
||||||
|
| | a | b | c | d |
|
||||||
|
| a | 0 | 10 | 30 | 60 |
|
||||||
|
| b | 10 | 0 | 20 | 50 |
|
||||||
|
| c | 30 | 20 | 0 | 30 |
|
||||||
|
| d | 60 | 50 | 30 | 0 |
|
||||||
|
|
||||||
|
When I request a travel time matrix I should get
|
||||||
|
| | a | b | c | d |
|
||||||
|
| a | 0 | 10 | 30 | 60 |
|
||||||
|
|
||||||
|
When I request a travel time matrix I should get
|
||||||
|
| | a |
|
||||||
|
| a | 0 |
|
||||||
|
| b | 10 |
|
||||||
|
| c | 30 |
|
||||||
|
| d | 60 |
|
||||||
|
|
||||||
|
|
||||||
|
Scenario: Testbot - Travel time matrix of small grid
|
||||||
|
Given the node map
|
||||||
|
"""
|
||||||
|
a b c
|
||||||
|
d e f
|
||||||
|
"""
|
||||||
|
|
||||||
|
And the ways
|
||||||
|
| nodes |
|
||||||
|
| abc |
|
||||||
|
| def |
|
||||||
|
| ad |
|
||||||
|
| be |
|
||||||
|
| cf |
|
||||||
|
|
||||||
|
When I request a travel time matrix I should get
|
||||||
|
| | a | b | e | f |
|
||||||
|
| a | 0 | 10 | 20 | 30 |
|
||||||
|
| b | 10 | 0 | 10 | 20 |
|
||||||
|
| e | 20 | 10 | 0 | 10 |
|
||||||
|
| f | 30 | 20 | 10 | 0 |
|
||||||
|
|
||||||
|
|
||||||
|
Scenario: Testbot - Travel time matrix of network with unroutable parts
|
||||||
|
Given the node map
|
||||||
|
"""
|
||||||
|
a b
|
||||||
|
"""
|
||||||
|
|
||||||
|
And the ways
|
||||||
|
| nodes | oneway |
|
||||||
|
| ab | yes |
|
||||||
|
|
||||||
|
When I request a travel time matrix I should get
|
||||||
|
| | a | b |
|
||||||
|
| a | 0 | 10 |
|
||||||
|
| b | | 0 |
|
||||||
|
|
||||||
|
|
||||||
|
Scenario: Testbot - Travel time matrix of network with oneways
|
||||||
|
Given the node map
|
||||||
|
"""
|
||||||
|
x a b y
|
||||||
|
d e
|
||||||
|
"""
|
||||||
|
|
||||||
|
And the ways
|
||||||
|
| nodes | oneway |
|
||||||
|
| abeda | yes |
|
||||||
|
| xa | |
|
||||||
|
| by | |
|
||||||
|
|
||||||
|
When I request a travel time matrix I should get
|
||||||
|
| | x | y | d | e |
|
||||||
|
| x | 0 | 30 | 40 | 30 |
|
||||||
|
| y | 50 | 0 | 30 | 20 |
|
||||||
|
| d | 20 | 30 | 0 | 30 |
|
||||||
|
| e | 30 | 40 | 10 | 0 |
|
||||||
|
|
||||||
|
|
||||||
|
Scenario: Testbot - Rectangular travel time matrix
|
||||||
|
Given the node map
|
||||||
|
"""
|
||||||
|
a b c
|
||||||
|
d e f
|
||||||
|
"""
|
||||||
|
|
||||||
|
And the ways
|
||||||
|
| nodes |
|
||||||
|
| abc |
|
||||||
|
| def |
|
||||||
|
| ad |
|
||||||
|
| be |
|
||||||
|
| cf |
|
||||||
|
|
||||||
|
When I request a travel time matrix I should get
|
||||||
|
| | a | b | e | f |
|
||||||
|
| a | 0 | 10 | 20 | 30 |
|
||||||
|
|
||||||
|
When I request a travel time matrix I should get
|
||||||
|
| | a |
|
||||||
|
| a | 0 |
|
||||||
|
| b | 10 |
|
||||||
|
| e | 20 |
|
||||||
|
| f | 30 |
|
||||||
|
|
||||||
|
When I request a travel time matrix I should get
|
||||||
|
| | a | b | e | f |
|
||||||
|
| a | 0 | 10 | 20 | 30 |
|
||||||
|
| b | 10 | 0 | 10 | 20 |
|
||||||
|
|
||||||
|
When I request a travel time matrix I should get
|
||||||
|
| | a | b |
|
||||||
|
| a | 0 | 10 |
|
||||||
|
| b | 10 | 0 |
|
||||||
|
| e | 20 | 10 |
|
||||||
|
| f | 30 | 20 |
|
||||||
|
|
||||||
|
When I request a travel time matrix I should get
|
||||||
|
| | a | b | e | f |
|
||||||
|
| a | 0 | 10 | 20 | 30 |
|
||||||
|
| b | 10 | 0 | 10 | 20 |
|
||||||
|
| e | 20 | 10 | 0 | 10 |
|
||||||
|
|
||||||
|
When I request a travel time matrix I should get
|
||||||
|
| | a | b | e |
|
||||||
|
| a | 0 | 10 | 20 |
|
||||||
|
| b | 10 | 0 | 10 |
|
||||||
|
| e | 20 | 10 | 0 |
|
||||||
|
| f | 30 | 20 | 10 |
|
||||||
|
|
||||||
|
When I request a travel time matrix I should get
|
||||||
|
| | a | b | e | f |
|
||||||
|
| a | 0 | 10 | 20 | 30 |
|
||||||
|
| b | 10 | 0 | 10 | 20 |
|
||||||
|
| e | 20 | 10 | 0 | 10 |
|
||||||
|
| f | 30 | 20 | 10 | 0 |
|
||||||
|
|
||||||
|
Scenario: Testbot - Travel time 3x2 matrix
|
||||||
|
Given the node map
|
||||||
|
"""
|
||||||
|
a b c
|
||||||
|
d e f
|
||||||
|
"""
|
||||||
|
|
||||||
|
And the ways
|
||||||
|
| nodes |
|
||||||
|
| abc |
|
||||||
|
| def |
|
||||||
|
| ad |
|
||||||
|
| be |
|
||||||
|
| cf |
|
||||||
|
|
||||||
|
When I request a travel time matrix I should get
|
||||||
|
| | b | e | f |
|
||||||
|
| a | 10 | 20 | 30 |
|
||||||
|
| b | 0 | 10 | 20 |
|
||||||
|
|
||||||
|
|
||||||
|
Scenario: Testbot - All coordinates are from same small component
|
||||||
|
Given a grid size of 300 meters
|
||||||
|
Given the extract extra arguments "--small-component-size 4"
|
||||||
|
Given the node map
|
||||||
|
"""
|
||||||
|
a b f
|
||||||
|
d e g
|
||||||
|
"""
|
||||||
|
|
||||||
|
And the ways
|
||||||
|
| nodes |
|
||||||
|
| ab |
|
||||||
|
| be |
|
||||||
|
| ed |
|
||||||
|
| da |
|
||||||
|
| fg |
|
||||||
|
|
||||||
|
When I request a travel time matrix I should get
|
||||||
|
| | f | g |
|
||||||
|
| f | 0 | 30 |
|
||||||
|
| g | 30 | 0 |
|
||||||
|
|
||||||
|
|
||||||
|
Scenario: Testbot - Coordinates are from different small component and snap to big CC
|
||||||
|
Given a grid size of 300 meters
|
||||||
|
Given the extract extra arguments "--small-component-size 4"
|
||||||
|
Given the node map
|
||||||
|
"""
|
||||||
|
a b f h
|
||||||
|
d e g i
|
||||||
|
"""
|
||||||
|
|
||||||
|
And the ways
|
||||||
|
| nodes |
|
||||||
|
| ab |
|
||||||
|
| be |
|
||||||
|
| ed |
|
||||||
|
| da |
|
||||||
|
| fg |
|
||||||
|
| hi |
|
||||||
|
|
||||||
|
When I request a travel time matrix I should get
|
||||||
|
| | f | g | h | i |
|
||||||
|
| f | 0 | 30 | 0 | 30 |
|
||||||
|
| g | 30 | 0 | 30 | 0 |
|
||||||
|
| h | 0 | 30 | 0 | 30 |
|
||||||
|
| i | 30 | 0 | 30 | 0 |
|
||||||
|
|
||||||
|
|
||||||
|
Scenario: Testbot - Travel time matrix with loops
|
||||||
|
Given the node map
|
||||||
|
"""
|
||||||
|
a 1 2 b
|
||||||
|
d 4 3 c
|
||||||
|
"""
|
||||||
|
|
||||||
|
And the ways
|
||||||
|
| nodes | oneway |
|
||||||
|
| ab | yes |
|
||||||
|
| bc | yes |
|
||||||
|
| cd | yes |
|
||||||
|
| da | yes |
|
||||||
|
|
||||||
|
When I request a travel time matrix I should get
|
||||||
|
| | 1 | 2 | 3 | 4 |
|
||||||
|
| 1 | 0 | 10 +-1 | 40 +-1 | 50 +-1 |
|
||||||
|
| 2 | 70 +-1 | 0 | 30 +-1 | 40 +-1 |
|
||||||
|
| 3 | 40 +-1 | 50 +-1 | 0 | 10 +-1 |
|
||||||
|
| 4 | 30 +-1 | 40 +-1 | 70 +-1 | 0 |
|
||||||
|
|
||||||
|
|
||||||
|
Scenario: Testbot - Travel time matrix based on segment durations
|
||||||
|
Given the profile file
|
||||||
|
"""
|
||||||
|
local functions = require('testbot')
|
||||||
|
functions.setup_testbot = functions.setup
|
||||||
|
|
||||||
|
functions.setup = function()
|
||||||
|
local profile = functions.setup_testbot()
|
||||||
|
profile.traffic_signal_penalty = 0
|
||||||
|
profile.u_turn_penalty = 0
|
||||||
|
return profile
|
||||||
|
end
|
||||||
|
|
||||||
|
functions.process_segment = function(profile, segment)
|
||||||
|
segment.weight = 2
|
||||||
|
segment.duration = 11
|
||||||
|
end
|
||||||
|
|
||||||
|
return functions
|
||||||
|
"""
|
||||||
|
|
||||||
|
And the node map
|
||||||
|
"""
|
||||||
|
a-b-c-d
|
||||||
|
.
|
||||||
|
e
|
||||||
|
"""
|
||||||
|
|
||||||
|
And the ways
|
||||||
|
| nodes |
|
||||||
|
| abcd |
|
||||||
|
| ce |
|
||||||
|
|
||||||
|
When I request a travel time matrix I should get
|
||||||
|
| | a | b | c | d | e |
|
||||||
|
| a | 0 | 11 | 22 | 33 | 33 |
|
||||||
|
| b | 11 | 0 | 11 | 22 | 22 |
|
||||||
|
| c | 22 | 11 | 0 | 11 | 11 |
|
||||||
|
| d | 33 | 22 | 11 | 0 | 22 |
|
||||||
|
| e | 33 | 22 | 11 | 22 | 0 |
|
||||||
|
|
||||||
|
|
||||||
|
Scenario: Testbot - Travel time matrix for alternative loop paths
|
||||||
|
Given the profile file
|
||||||
|
"""
|
||||||
|
local functions = require('testbot')
|
||||||
|
functions.setup_testbot = functions.setup
|
||||||
|
|
||||||
|
functions.setup = function()
|
||||||
|
local profile = functions.setup_testbot()
|
||||||
|
profile.traffic_signal_penalty = 0
|
||||||
|
profile.u_turn_penalty = 0
|
||||||
|
profile.weight_precision = 3
|
||||||
|
return profile
|
||||||
|
end
|
||||||
|
|
||||||
|
functions.process_segment = function(profile, segment)
|
||||||
|
segment.weight = 777
|
||||||
|
segment.duration = 3
|
||||||
|
end
|
||||||
|
|
||||||
|
return functions
|
||||||
|
"""
|
||||||
|
And the node map
|
||||||
|
"""
|
||||||
|
a 2 1 b
|
||||||
|
7 4
|
||||||
|
8 3
|
||||||
|
c 5 6 d
|
||||||
|
"""
|
||||||
|
|
||||||
|
And the ways
|
||||||
|
| nodes | oneway |
|
||||||
|
| ab | yes |
|
||||||
|
| bd | yes |
|
||||||
|
| dc | yes |
|
||||||
|
| ca | yes |
|
||||||
|
|
||||||
|
When I request a travel time matrix I should get
|
||||||
|
| | 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 |
|
||||||
|
| 1 | 0 | 11 | 3 | 2 | 6 | 5 | 8.9 | 7.9 |
|
||||||
|
| 2 | 1 | 0 | 4 | 3 | 7 | 6 | 9.9 | 8.9 |
|
||||||
|
| 3 | 9 | 8 | 0 | 11 | 3 | 2 | 5.9 | 4.9 |
|
||||||
|
| 4 | 10 | 9 | 1 | 0 | 4 | 3 | 6.9 | 5.9 |
|
||||||
|
| 5 | 6 | 5 | 9 | 8 | 0 | 11 | 2.9 | 1.9 |
|
||||||
|
| 6 | 7 | 6 | 10 | 9 | 1 | 0 | 3.9 | 2.9 |
|
||||||
|
| 7 | 3.1 | 2.1 | 6.1 | 5.1 | 9.1 | 8.1 | 0 | 11 |
|
||||||
|
| 8 | 4.1 | 3.1 | 7.1 | 6.1 | 10.1 | 9.1 | 1 | 0 |
|
||||||
|
|
||||||
|
|
||||||
|
Scenario: Testbot - Travel time matrix with ties
|
||||||
|
Given the profile file
|
||||||
|
"""
|
||||||
|
local functions = require('testbot')
|
||||||
|
functions.process_segment = function(profile, segment)
|
||||||
|
segment.weight = 1
|
||||||
|
segment.duration = 1
|
||||||
|
end
|
||||||
|
functions.process_turn = function(profile, turn)
|
||||||
|
if turn.angle >= 0 then
|
||||||
|
turn.duration = 16
|
||||||
|
else
|
||||||
|
turn.duration = 4
|
||||||
|
end
|
||||||
|
turn.weight = 0
|
||||||
|
end
|
||||||
|
return functions
|
||||||
|
"""
|
||||||
|
And the node map
|
||||||
|
"""
|
||||||
|
a b
|
||||||
|
|
||||||
|
c d
|
||||||
|
"""
|
||||||
|
|
||||||
|
And the ways
|
||||||
|
| nodes |
|
||||||
|
| ab |
|
||||||
|
| ac |
|
||||||
|
| bd |
|
||||||
|
| dc |
|
||||||
|
|
||||||
|
When I route I should get
|
||||||
|
| from | to | route | distance | time | weight |
|
||||||
|
| a | c | ac,ac | 200m | 5s | 5 |
|
||||||
|
|
||||||
|
When I request a travel time matrix I should get
|
||||||
|
| | a | b | c | d |
|
||||||
|
| a | 0 | 1 | 5 | 10 |
|
||||||
|
|
||||||
|
When I request a travel time matrix I should get
|
||||||
|
| | a |
|
||||||
|
| a | 0 |
|
||||||
|
| b | 1 |
|
||||||
|
| c | 15 |
|
||||||
|
| d | 10 |
|
||||||
|
|
||||||
|
Scenario: Testbot - OneToMany vs ManyToOne
|
||||||
|
Given the node map
|
||||||
|
"""
|
||||||
|
a b
|
||||||
|
c
|
||||||
|
"""
|
||||||
|
|
||||||
|
And the ways
|
||||||
|
| nodes | oneway |
|
||||||
|
| ab | yes |
|
||||||
|
| ac | |
|
||||||
|
| bc | |
|
||||||
|
|
||||||
|
When I request a travel time matrix I should get
|
||||||
|
| | a | b |
|
||||||
|
| b | 24.1 | 0 |
|
||||||
|
|
||||||
|
When I request a travel time matrix I should get
|
||||||
|
| | a |
|
||||||
|
| a | 0 |
|
||||||
|
| b | 24.1 |
|
||||||
@@ -39,5 +39,64 @@ Feature: Fixed bugs, kept to check for regressions
|
|||||||
| de | yes |
|
| de | yes |
|
||||||
|
|
||||||
When I route I should get
|
When I route I should get
|
||||||
| from | to | route |
|
| from | to | route |
|
||||||
| 1 | 2 | bcd,bcd |
|
| 1 | 2 | bcd,bcd |
|
||||||
|
|
||||||
|
#############################
|
||||||
|
# This test models the OSM map at the location for
|
||||||
|
# https://github.com/Project-OSRM/osrm-backend/issues/5039
|
||||||
|
#############################
|
||||||
|
Scenario: Mixed Entry and Exit and segregated
|
||||||
|
Given the profile file "car" initialized with
|
||||||
|
"""
|
||||||
|
profile.properties.left_hand_driving = true
|
||||||
|
"""
|
||||||
|
Given the node locations
|
||||||
|
| node | lon | lat |
|
||||||
|
| a | 171.12889297029 | -42.58425289548 |
|
||||||
|
| b | 171.1299357 | -42.5849295 |
|
||||||
|
| c | 171.1295427 | -42.5849385 |
|
||||||
|
| d | 171.1297356 | -42.5852029 |
|
||||||
|
| e | 171.1296909 | -42.5851986 |
|
||||||
|
| f | 171.1295097 | -42.585007 |
|
||||||
|
| g | 171.1298225 | -42.5851928 |
|
||||||
|
| h | 171.1300262 | -42.5859122 |
|
||||||
|
| i | 171.1292651 | -42.584698 |
|
||||||
|
| j | 171.1297209 | -42.5848569 |
|
||||||
|
| k | 171.1297188 | -42.5854056 |
|
||||||
|
| l | 171.1298326 | -42.5857266 |
|
||||||
|
| m | 171.1298871 | -42.5848922 |
|
||||||
|
| n | 171.1296505 | -42.585189 |
|
||||||
|
| o | 171.1295206 | -42.5850862 |
|
||||||
|
| p | 171.1296106 | -42.5848862 |
|
||||||
|
| q | 171.1299784 | -42.5850191 |
|
||||||
|
| r | 171.1298867 | -42.5851671 |
|
||||||
|
| s | 171.1306955 | -42.5845812 |
|
||||||
|
| t | 171.129525 | -42.584807 |
|
||||||
|
| u | 171.1299705 | -42.584984 |
|
||||||
|
| v | 171.1299067 | -42.5849073 |
|
||||||
|
| w | 171.1302061 | -42.5848173 |
|
||||||
|
| x | 171.12975 | -42.5855753 |
|
||||||
|
| y | 171.129969 | -42.585079 |
|
||||||
|
| 1 | 171.131511926651| -42.584306746421966 |
|
||||||
|
| 2 | 171.128743886947| -42.58414875714669 |
|
||||||
|
And the ways
|
||||||
|
| nodes | highway | maxspeed | name | ref | surface | junction | oneway |
|
||||||
|
| ws | primary | 100 | Taramakau Highway | SH 6 | asphalt | | |
|
||||||
|
| kxlh | trunk | | Otira Highway | SH 73 | | | |
|
||||||
|
| ai | primary | 100 | Kumara Junction Highway | SH 6 | asphalt | | |
|
||||||
|
| qyrgdenof | primary | 100 | Kumara Junction | | | roundabout | yes |
|
||||||
|
| ke | trunk | | Otira Highway | SH 73 | | | yes |
|
||||||
|
| itj | primary | 100 | Kumara Junction Highway | SH 6 | | | yes |
|
||||||
|
| gk | trunk | | Otira Highway | SH 73 | | | yes |
|
||||||
|
| fi | primary | 100 | Kumara Junction Highway | SH 6 | | | yes |
|
||||||
|
| wq | primary | 100 | Taramakau Highway | SH 6 | | | yes |
|
||||||
|
| vw | primary | 100 | Taramakau Highway | SH 6 | | | yes |
|
||||||
|
| vbuq | primary | 100 | Kumara Junction | | | roundabout | yes |
|
||||||
|
| jmv | primary | 100 | Kumara Junction | | | roundabout | yes |
|
||||||
|
| fcpj | primary | 100 | Kumara Junction | | | roundabout | yes |
|
||||||
|
|
||||||
|
When I route I should get
|
||||||
|
| waypoints | route | turns |
|
||||||
|
| 1,2 | Taramakau Highway,Kumara Junction Highway,Kumara Junction Highway,Kumara Junction Highway | depart,Kumara Junction-exit-2,exit rotary slight left,arrive |
|
||||||
|
|
||||||
|
|||||||
@@ -106,6 +106,40 @@ Feature: Multi level routing
|
|||||||
| l | 144.7 | 60 |
|
| l | 144.7 | 60 |
|
||||||
| o | 124.7 | 0 |
|
| o | 124.7 | 0 |
|
||||||
|
|
||||||
|
|
||||||
|
When I request a travel distance matrix I should get
|
||||||
|
| | a | f | l | o |
|
||||||
|
| a | 0+-2 | 2287+-2 | 1443+-2 | 1243+-2 |
|
||||||
|
| f | 2284+-2 | 0+-2 | 1241+-2 | 1443+-2 |
|
||||||
|
| l | 1443+-2 | 1244+-2 | 0+-2 | 600+-2 |
|
||||||
|
| o | 1243+-2 | 1444+-2 | 600+-2 | 0+-2 |
|
||||||
|
|
||||||
|
When I request a travel distance matrix I should get
|
||||||
|
| | a | f | l | o |
|
||||||
|
| a | 0 | 2287.2+-2 | 1443+-2 | 1243+-2 |
|
||||||
|
|
||||||
|
When I request a travel distance matrix I should get
|
||||||
|
| | a |
|
||||||
|
| a | 0 |
|
||||||
|
| f | 2284.5+-2 |
|
||||||
|
| l | 1443.1 |
|
||||||
|
| o | 1243 |
|
||||||
|
|
||||||
|
When I request a travel distance matrix I should get
|
||||||
|
| | a | f | l | o |
|
||||||
|
| a | 0 | 2287+-2 | 1443+-2 | 1243+-2 |
|
||||||
|
| o | 1243 | 1444+-2 | 600+-2 | 0+-2 |
|
||||||
|
|
||||||
|
|
||||||
|
When I request a travel distance matrix I should get
|
||||||
|
| | a | o |
|
||||||
|
| a | 0+-2 | 1243+-2 |
|
||||||
|
| f | 2284+-2 | 1443+-2 |
|
||||||
|
| l | 1443+-2 | 600+-2 |
|
||||||
|
| o | 1243+-2 | 0+-2 |
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
Scenario: Testbot - Multi level routing: horizontal road
|
Scenario: Testbot - Multi level routing: horizontal road
|
||||||
Given the node map
|
Given the node map
|
||||||
"""
|
"""
|
||||||
|
|||||||
@@ -54,7 +54,7 @@ Feature: Traffic - speeds
|
|||||||
| a | d | ad,ad | 27 km/h | 1275.7,0 | 1 |
|
| a | d | ad,ad | 27 km/h | 1275.7,0 | 1 |
|
||||||
| d | c | dc,dc | 36 km/h | 956.8,0 | 0 |
|
| d | c | dc,dc | 36 km/h | 956.8,0 | 0 |
|
||||||
| g | b | fb,fb | 36 km/h | 164.7,0 | 0 |
|
| g | b | fb,fb | 36 km/h | 164.7,0 | 0 |
|
||||||
| a | g | ad,df,fb,fb | 30 km/h | 1275.7,487.5,304.7,0 | 1:0:0 |
|
| a | g | ad,df,fb,fb | 30 km/h | 1295.7,487.5,304.7,0 | 1:0:0 |
|
||||||
|
|
||||||
|
|
||||||
Scenario: Weighting based on speed file weights, ETA based on file durations
|
Scenario: Weighting based on speed file weights, ETA based on file durations
|
||||||
|
|||||||
@@ -72,8 +72,14 @@ struct ContractorConfig final : storage::IOConfig
|
|||||||
// The remaining vertices form the core of the hierarchy
|
// The remaining vertices form the core of the hierarchy
|
||||||
//(e.g. 0.8 contracts 80 percent of the hierarchy, leaving a core of 20%)
|
//(e.g. 0.8 contracts 80 percent of the hierarchy, leaving a core of 20%)
|
||||||
double core_factor;
|
double core_factor;
|
||||||
|
|
||||||
|
// Whether to store distances for CH edges in addition to duration/weight
|
||||||
|
// Defaults to false. Setting to true will require more storage/memory,
|
||||||
|
// but avoids the need for path unpacking to learn the distance of a CH
|
||||||
|
// route (useful for faster distance results in table queries)
|
||||||
|
bool cache_distances;
|
||||||
};
|
};
|
||||||
}
|
} // namespace contractor
|
||||||
}
|
} // namespace osrm
|
||||||
|
|
||||||
#endif // EXTRACTOR_OPTIONS_HPP
|
#endif // EXTRACTOR_OPTIONS_HPP
|
||||||
|
|||||||
@@ -12,23 +12,26 @@ namespace contractor
|
|||||||
struct ContractorEdgeData
|
struct ContractorEdgeData
|
||||||
{
|
{
|
||||||
ContractorEdgeData()
|
ContractorEdgeData()
|
||||||
: weight(0), duration(0), id(0), originalEdges(0), shortcut(0), forward(0), backward(0)
|
: weight(0), duration(0), distance(0), id(0), originalEdges(0), shortcut(0), forward(0),
|
||||||
|
backward(0)
|
||||||
{
|
{
|
||||||
}
|
}
|
||||||
ContractorEdgeData(EdgeWeight weight,
|
ContractorEdgeData(EdgeWeight weight,
|
||||||
EdgeWeight duration,
|
EdgeWeight duration,
|
||||||
|
EdgeDistance distance,
|
||||||
unsigned original_edges,
|
unsigned original_edges,
|
||||||
unsigned id,
|
unsigned id,
|
||||||
bool shortcut,
|
bool shortcut,
|
||||||
bool forward,
|
bool forward,
|
||||||
bool backward)
|
bool backward)
|
||||||
: weight(weight), duration(duration), id(id),
|
: weight(weight), duration(duration), distance(distance), id(id),
|
||||||
originalEdges(std::min((1u << 29) - 1u, original_edges)), shortcut(shortcut),
|
originalEdges(std::min((1u << 29) - 1u, original_edges)), shortcut(shortcut),
|
||||||
forward(forward), backward(backward)
|
forward(forward), backward(backward)
|
||||||
{
|
{
|
||||||
}
|
}
|
||||||
EdgeWeight weight;
|
EdgeWeight weight;
|
||||||
EdgeWeight duration;
|
EdgeWeight duration;
|
||||||
|
EdgeDistance distance;
|
||||||
unsigned id;
|
unsigned id;
|
||||||
unsigned originalEdges : 29;
|
unsigned originalEdges : 29;
|
||||||
bool shortcut : 1;
|
bool shortcut : 1;
|
||||||
|
|||||||
@@ -41,6 +41,7 @@ ContractorGraph toContractorGraph(NodeID number_of_nodes, InputEdgeContainer inp
|
|||||||
input_edge.target,
|
input_edge.target,
|
||||||
std::max(input_edge.data.weight, 1),
|
std::max(input_edge.data.weight, 1),
|
||||||
input_edge.data.duration,
|
input_edge.data.duration,
|
||||||
|
input_edge.data.distance,
|
||||||
1,
|
1,
|
||||||
input_edge.data.turn_id,
|
input_edge.data.turn_id,
|
||||||
false,
|
false,
|
||||||
@@ -51,6 +52,7 @@ ContractorGraph toContractorGraph(NodeID number_of_nodes, InputEdgeContainer inp
|
|||||||
input_edge.source,
|
input_edge.source,
|
||||||
std::max(input_edge.data.weight, 1),
|
std::max(input_edge.data.weight, 1),
|
||||||
input_edge.data.duration,
|
input_edge.data.duration,
|
||||||
|
input_edge.data.distance,
|
||||||
1,
|
1,
|
||||||
input_edge.data.turn_id,
|
input_edge.data.turn_id,
|
||||||
false,
|
false,
|
||||||
@@ -82,6 +84,7 @@ ContractorGraph toContractorGraph(NodeID number_of_nodes, InputEdgeContainer inp
|
|||||||
forward_edge.data.originalEdges = reverse_edge.data.originalEdges = 1;
|
forward_edge.data.originalEdges = reverse_edge.data.originalEdges = 1;
|
||||||
forward_edge.data.weight = reverse_edge.data.weight = INVALID_EDGE_WEIGHT;
|
forward_edge.data.weight = reverse_edge.data.weight = INVALID_EDGE_WEIGHT;
|
||||||
forward_edge.data.duration = reverse_edge.data.duration = MAXIMAL_EDGE_DURATION;
|
forward_edge.data.duration = reverse_edge.data.duration = MAXIMAL_EDGE_DURATION;
|
||||||
|
forward_edge.data.distance = reverse_edge.data.distance = MAXIMAL_EDGE_DISTANCE;
|
||||||
// remove parallel edges
|
// remove parallel edges
|
||||||
while (i < edges.size() && edges[i].source == source && edges[i].target == target)
|
while (i < edges.size() && edges[i].source == source && edges[i].target == target)
|
||||||
{
|
{
|
||||||
@@ -90,12 +93,16 @@ ContractorGraph toContractorGraph(NodeID number_of_nodes, InputEdgeContainer inp
|
|||||||
forward_edge.data.weight = std::min(edges[i].data.weight, forward_edge.data.weight);
|
forward_edge.data.weight = std::min(edges[i].data.weight, forward_edge.data.weight);
|
||||||
forward_edge.data.duration =
|
forward_edge.data.duration =
|
||||||
std::min(edges[i].data.duration, forward_edge.data.duration);
|
std::min(edges[i].data.duration, forward_edge.data.duration);
|
||||||
|
forward_edge.data.distance =
|
||||||
|
std::min(edges[i].data.distance, forward_edge.data.distance);
|
||||||
}
|
}
|
||||||
if (edges[i].data.backward)
|
if (edges[i].data.backward)
|
||||||
{
|
{
|
||||||
reverse_edge.data.weight = std::min(edges[i].data.weight, reverse_edge.data.weight);
|
reverse_edge.data.weight = std::min(edges[i].data.weight, reverse_edge.data.weight);
|
||||||
reverse_edge.data.duration =
|
reverse_edge.data.duration =
|
||||||
std::min(edges[i].data.duration, reverse_edge.data.duration);
|
std::min(edges[i].data.duration, reverse_edge.data.duration);
|
||||||
|
reverse_edge.data.distance =
|
||||||
|
std::min(edges[i].data.distance, reverse_edge.data.distance);
|
||||||
}
|
}
|
||||||
++i;
|
++i;
|
||||||
}
|
}
|
||||||
@@ -151,6 +158,7 @@ template <class Edge, typename GraphT> inline std::vector<Edge> toEdges(GraphT g
|
|||||||
BOOST_ASSERT_MSG(SPECIAL_NODEID != new_edge.target, "Target id invalid");
|
BOOST_ASSERT_MSG(SPECIAL_NODEID != new_edge.target, "Target id invalid");
|
||||||
new_edge.data.weight = data.weight;
|
new_edge.data.weight = data.weight;
|
||||||
new_edge.data.duration = data.duration;
|
new_edge.data.duration = data.duration;
|
||||||
|
new_edge.data.distance = data.distance;
|
||||||
new_edge.data.shortcut = data.shortcut;
|
new_edge.data.shortcut = data.shortcut;
|
||||||
new_edge.data.turn_id = data.id;
|
new_edge.data.turn_id = data.id;
|
||||||
BOOST_ASSERT_MSG(new_edge.data.turn_id != INT_MAX, // 2^31
|
BOOST_ASSERT_MSG(new_edge.data.turn_id != INT_MAX, // 2^31
|
||||||
|
|||||||
@@ -17,7 +17,8 @@ struct QueryEdge
|
|||||||
struct EdgeData
|
struct EdgeData
|
||||||
{
|
{
|
||||||
explicit EdgeData()
|
explicit EdgeData()
|
||||||
: turn_id(0), shortcut(false), weight(0), duration(0), forward(false), backward(false)
|
: turn_id(0), shortcut(false), weight(0), duration(0), forward(false), backward(false),
|
||||||
|
distance(0)
|
||||||
{
|
{
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -25,10 +26,11 @@ struct QueryEdge
|
|||||||
const bool shortcut,
|
const bool shortcut,
|
||||||
const EdgeWeight weight,
|
const EdgeWeight weight,
|
||||||
const EdgeWeight duration,
|
const EdgeWeight duration,
|
||||||
|
const EdgeDistance distance,
|
||||||
const bool forward,
|
const bool forward,
|
||||||
const bool backward)
|
const bool backward)
|
||||||
: turn_id(turn_id), shortcut(shortcut), weight(weight), duration(duration),
|
: turn_id(turn_id), shortcut(shortcut), weight(weight), duration(duration),
|
||||||
forward(forward), backward(backward)
|
forward(forward), backward(backward), distance(distance)
|
||||||
{
|
{
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -40,6 +42,7 @@ struct QueryEdge
|
|||||||
turn_id = other.id;
|
turn_id = other.id;
|
||||||
forward = other.forward;
|
forward = other.forward;
|
||||||
backward = other.backward;
|
backward = other.backward;
|
||||||
|
distance = other.distance;
|
||||||
}
|
}
|
||||||
// this ID is either the middle node of the shortcut, or the ID of the edge based node (node
|
// this ID is either the middle node of the shortcut, or the ID of the edge based node (node
|
||||||
// based edge) storing the appropriate data. If `shortcut` is set to true, we get the middle
|
// based edge) storing the appropriate data. If `shortcut` is set to true, we get the middle
|
||||||
@@ -50,6 +53,7 @@ struct QueryEdge
|
|||||||
EdgeWeight duration : 30;
|
EdgeWeight duration : 30;
|
||||||
std::uint32_t forward : 1;
|
std::uint32_t forward : 1;
|
||||||
std::uint32_t backward : 1;
|
std::uint32_t backward : 1;
|
||||||
|
EdgeDistance distance;
|
||||||
} data;
|
} data;
|
||||||
|
|
||||||
QueryEdge() : source(SPECIAL_NODEID), target(SPECIAL_NODEID) {}
|
QueryEdge() : source(SPECIAL_NODEID), target(SPECIAL_NODEID) {}
|
||||||
@@ -69,10 +73,11 @@ struct QueryEdge
|
|||||||
return (source == right.source && target == right.target &&
|
return (source == right.source && target == right.target &&
|
||||||
data.weight == right.data.weight && data.duration == right.data.duration &&
|
data.weight == right.data.weight && data.duration == right.data.duration &&
|
||||||
data.shortcut == right.data.shortcut && data.forward == right.data.forward &&
|
data.shortcut == right.data.shortcut && data.forward == right.data.forward &&
|
||||||
data.backward == right.data.backward && data.turn_id == right.data.turn_id);
|
data.backward == right.data.backward && data.turn_id == right.data.turn_id &&
|
||||||
|
data.distance == right.data.distance);
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
}
|
} // namespace contractor
|
||||||
}
|
} // namespace osrm
|
||||||
|
|
||||||
#endif // QUERYEDGE_HPP
|
#endif // QUERYEDGE_HPP
|
||||||
|
|||||||
@@ -21,7 +21,8 @@ struct CustomizationConfig final : storage::IOConfig
|
|||||||
".osrm.partition",
|
".osrm.partition",
|
||||||
".osrm.cells",
|
".osrm.cells",
|
||||||
".osrm.ebg_nodes",
|
".osrm.ebg_nodes",
|
||||||
".osrm.properties"},
|
".osrm.properties",
|
||||||
|
".osrm.enw"},
|
||||||
{},
|
{},
|
||||||
{".osrm.cell_metrics", ".osrm.mldgr"}),
|
{".osrm.cell_metrics", ".osrm.mldgr"}),
|
||||||
requested_num_threads(0)
|
requested_num_threads(0)
|
||||||
|
|||||||
@@ -16,28 +16,109 @@ namespace osrm
|
|||||||
namespace customizer
|
namespace customizer
|
||||||
{
|
{
|
||||||
|
|
||||||
using EdgeBasedGraphEdgeData = partitioner::EdgeBasedGraphEdgeData;
|
struct EdgeBasedGraphEdgeData
|
||||||
|
|
||||||
struct MultiLevelEdgeBasedGraph
|
|
||||||
: public partitioner::MultiLevelGraph<EdgeBasedGraphEdgeData, storage::Ownership::Container>
|
|
||||||
{
|
{
|
||||||
using Base =
|
NodeID turn_id; // ID of the edge based node (node based edge)
|
||||||
partitioner::MultiLevelGraph<EdgeBasedGraphEdgeData, storage::Ownership::Container>;
|
|
||||||
using Base::Base;
|
|
||||||
};
|
};
|
||||||
|
|
||||||
struct MultiLevelEdgeBasedGraphView
|
template <typename EdgeDataT, storage::Ownership Ownership> class MultiLevelGraph;
|
||||||
: public partitioner::MultiLevelGraph<EdgeBasedGraphEdgeData, storage::Ownership::View>
|
|
||||||
|
namespace serialization
|
||||||
{
|
{
|
||||||
using Base = partitioner::MultiLevelGraph<EdgeBasedGraphEdgeData, storage::Ownership::View>;
|
template <typename EdgeDataT, storage::Ownership Ownership>
|
||||||
using Base::Base;
|
void read(storage::tar::FileReader &reader,
|
||||||
|
const std::string &name,
|
||||||
|
MultiLevelGraph<EdgeDataT, Ownership> &graph);
|
||||||
|
|
||||||
|
template <typename EdgeDataT, storage::Ownership Ownership>
|
||||||
|
void write(storage::tar::FileWriter &writer,
|
||||||
|
const std::string &name,
|
||||||
|
const MultiLevelGraph<EdgeDataT, Ownership> &graph);
|
||||||
|
}
|
||||||
|
|
||||||
|
template <typename EdgeDataT, storage::Ownership Ownership>
|
||||||
|
class MultiLevelGraph : public partitioner::MultiLevelGraph<EdgeDataT, Ownership>
|
||||||
|
{
|
||||||
|
private:
|
||||||
|
using SuperT = partitioner::MultiLevelGraph<EdgeDataT, Ownership>;
|
||||||
|
using PartitionerGraphT = partitioner::MultiLevelGraph<partitioner::EdgeBasedGraphEdgeData,
|
||||||
|
storage::Ownership::Container>;
|
||||||
|
template <typename T> using Vector = util::ViewOrVector<T, Ownership>;
|
||||||
|
|
||||||
|
public:
|
||||||
|
using NodeArrayEntry = typename SuperT::NodeArrayEntry;
|
||||||
|
using EdgeArrayEntry = typename SuperT::EdgeArrayEntry;
|
||||||
|
using EdgeOffset = typename SuperT::EdgeOffset;
|
||||||
|
|
||||||
|
MultiLevelGraph() = default;
|
||||||
|
MultiLevelGraph(MultiLevelGraph &&) = default;
|
||||||
|
MultiLevelGraph(const MultiLevelGraph &) = default;
|
||||||
|
MultiLevelGraph &operator=(MultiLevelGraph &&) = default;
|
||||||
|
MultiLevelGraph &operator=(const MultiLevelGraph &) = default;
|
||||||
|
|
||||||
|
MultiLevelGraph(PartitionerGraphT &&graph,
|
||||||
|
Vector<EdgeWeight> node_weights_,
|
||||||
|
Vector<EdgeDuration> node_durations_)
|
||||||
|
: node_weights(std::move(node_weights_)), node_durations(std::move(node_durations_))
|
||||||
|
{
|
||||||
|
util::ViewOrVector<PartitionerGraphT::EdgeArrayEntry, storage::Ownership::Container>
|
||||||
|
original_edge_array;
|
||||||
|
|
||||||
|
std::tie(SuperT::node_array,
|
||||||
|
original_edge_array,
|
||||||
|
SuperT::node_to_edge_offset,
|
||||||
|
SuperT::connectivity_checksum) = std::move(graph).data();
|
||||||
|
|
||||||
|
SuperT::edge_array.reserve(original_edge_array.size());
|
||||||
|
for (const auto &edge : original_edge_array)
|
||||||
|
{
|
||||||
|
SuperT::edge_array.push_back({edge.target, {edge.data.turn_id}});
|
||||||
|
is_forward_edge.push_back(edge.data.forward);
|
||||||
|
is_backward_edge.push_back(edge.data.backward);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
MultiLevelGraph(Vector<NodeArrayEntry> node_array_,
|
||||||
|
Vector<EdgeArrayEntry> edge_array_,
|
||||||
|
Vector<EdgeOffset> node_to_edge_offset_,
|
||||||
|
Vector<EdgeWeight> node_weights_,
|
||||||
|
Vector<EdgeDuration> node_durations_,
|
||||||
|
Vector<bool> is_forward_edge_,
|
||||||
|
Vector<bool> is_backward_edge_)
|
||||||
|
: SuperT(std::move(node_array_), std::move(edge_array_), std::move(node_to_edge_offset_)),
|
||||||
|
node_weights(std::move(node_weights_)), node_durations(std::move(node_durations_)),
|
||||||
|
is_forward_edge(is_forward_edge_), is_backward_edge(is_backward_edge_)
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
|
EdgeWeight GetNodeWeight(NodeID node) const { return node_weights[node]; }
|
||||||
|
|
||||||
|
EdgeWeight GetNodeDuration(NodeID node) const { return node_durations[node]; }
|
||||||
|
|
||||||
|
bool IsForwardEdge(EdgeID edge) const { return is_forward_edge[edge]; }
|
||||||
|
|
||||||
|
bool IsBackwardEdge(EdgeID edge) const { return is_backward_edge[edge]; }
|
||||||
|
|
||||||
|
friend void
|
||||||
|
serialization::read<EdgeDataT, Ownership>(storage::tar::FileReader &reader,
|
||||||
|
const std::string &name,
|
||||||
|
MultiLevelGraph<EdgeDataT, Ownership> &graph);
|
||||||
|
friend void
|
||||||
|
serialization::write<EdgeDataT, Ownership>(storage::tar::FileWriter &writer,
|
||||||
|
const std::string &name,
|
||||||
|
const MultiLevelGraph<EdgeDataT, Ownership> &graph);
|
||||||
|
|
||||||
|
protected:
|
||||||
|
Vector<EdgeWeight> node_weights;
|
||||||
|
Vector<EdgeDuration> node_durations;
|
||||||
|
Vector<bool> is_forward_edge;
|
||||||
|
Vector<bool> is_backward_edge;
|
||||||
};
|
};
|
||||||
|
|
||||||
struct StaticEdgeBasedGraphEdge : MultiLevelEdgeBasedGraph::InputEdge
|
using MultiLevelEdgeBasedGraph =
|
||||||
{
|
MultiLevelGraph<EdgeBasedGraphEdgeData, storage::Ownership::Container>;
|
||||||
using Base = MultiLevelEdgeBasedGraph::InputEdge;
|
using MultiLevelEdgeBasedGraphView =
|
||||||
using Base::Base;
|
MultiLevelGraph<EdgeBasedGraphEdgeData, storage::Ownership::View>;
|
||||||
};
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -73,6 +73,39 @@ writeCellMetrics(const boost::filesystem::path &path,
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// reads .osrm.mldgr file
|
||||||
|
template <typename MultiLevelGraphT>
|
||||||
|
inline void readGraph(const boost::filesystem::path &path,
|
||||||
|
MultiLevelGraphT &graph,
|
||||||
|
std::uint32_t &connectivity_checksum)
|
||||||
|
{
|
||||||
|
static_assert(std::is_same<customizer::MultiLevelEdgeBasedGraphView, MultiLevelGraphT>::value ||
|
||||||
|
std::is_same<customizer::MultiLevelEdgeBasedGraph, MultiLevelGraphT>::value,
|
||||||
|
"");
|
||||||
|
|
||||||
|
storage::tar::FileReader reader{path, storage::tar::FileReader::VerifyFingerprint};
|
||||||
|
|
||||||
|
reader.ReadInto("/mld/connectivity_checksum", connectivity_checksum);
|
||||||
|
serialization::read(reader, "/mld/multilevelgraph", graph);
|
||||||
|
}
|
||||||
|
|
||||||
|
// writes .osrm.mldgr file
|
||||||
|
template <typename MultiLevelGraphT>
|
||||||
|
inline void writeGraph(const boost::filesystem::path &path,
|
||||||
|
const MultiLevelGraphT &graph,
|
||||||
|
const std::uint32_t connectivity_checksum)
|
||||||
|
{
|
||||||
|
static_assert(std::is_same<customizer::MultiLevelEdgeBasedGraphView, MultiLevelGraphT>::value ||
|
||||||
|
std::is_same<customizer::MultiLevelEdgeBasedGraph, MultiLevelGraphT>::value,
|
||||||
|
"");
|
||||||
|
|
||||||
|
storage::tar::FileWriter writer{path, storage::tar::FileWriter::GenerateFingerprint};
|
||||||
|
|
||||||
|
writer.WriteElementCount64("/mld/connectivity_checksum", 1);
|
||||||
|
writer.WriteFrom("/mld/connectivity_checksum", connectivity_checksum);
|
||||||
|
serialization::write(writer, "/mld/multilevelgraph", graph);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,6 +1,8 @@
|
|||||||
#ifndef OSRM_CUSTOMIZER_SERIALIZATION_HPP
|
#ifndef OSRM_CUSTOMIZER_SERIALIZATION_HPP
|
||||||
#define OSRM_CUSTOMIZER_SERIALIZATION_HPP
|
#define OSRM_CUSTOMIZER_SERIALIZATION_HPP
|
||||||
|
|
||||||
|
#include "customizer/edge_based_graph.hpp"
|
||||||
|
|
||||||
#include "partitioner/cell_storage.hpp"
|
#include "partitioner/cell_storage.hpp"
|
||||||
|
|
||||||
#include "storage/serialization.hpp"
|
#include "storage/serialization.hpp"
|
||||||
@@ -31,6 +33,34 @@ inline void write(storage::tar::FileWriter &writer,
|
|||||||
storage::serialization::write(writer, name + "/weights", metric.weights);
|
storage::serialization::write(writer, name + "/weights", metric.weights);
|
||||||
storage::serialization::write(writer, name + "/durations", metric.durations);
|
storage::serialization::write(writer, name + "/durations", metric.durations);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
template <typename EdgeDataT, storage::Ownership Ownership>
|
||||||
|
inline void read(storage::tar::FileReader &reader,
|
||||||
|
const std::string &name,
|
||||||
|
MultiLevelGraph<EdgeDataT, Ownership> &graph)
|
||||||
|
{
|
||||||
|
storage::serialization::read(reader, name + "/node_array", graph.node_array);
|
||||||
|
storage::serialization::read(reader, name + "/node_weights", graph.node_weights);
|
||||||
|
storage::serialization::read(reader, name + "/node_durations", graph.node_durations);
|
||||||
|
storage::serialization::read(reader, name + "/edge_array", graph.edge_array);
|
||||||
|
storage::serialization::read(reader, name + "/is_forward_edge", graph.is_forward_edge);
|
||||||
|
storage::serialization::read(reader, name + "/is_backward_edge", graph.is_backward_edge);
|
||||||
|
storage::serialization::read(reader, name + "/node_to_edge_offset", graph.node_to_edge_offset);
|
||||||
|
}
|
||||||
|
|
||||||
|
template <typename EdgeDataT, storage::Ownership Ownership>
|
||||||
|
inline void write(storage::tar::FileWriter &writer,
|
||||||
|
const std::string &name,
|
||||||
|
const MultiLevelGraph<EdgeDataT, Ownership> &graph)
|
||||||
|
{
|
||||||
|
storage::serialization::write(writer, name + "/node_array", graph.node_array);
|
||||||
|
storage::serialization::write(writer, name + "/node_weights", graph.node_weights);
|
||||||
|
storage::serialization::write(writer, name + "/node_durations", graph.node_durations);
|
||||||
|
storage::serialization::write(writer, name + "/edge_array", graph.edge_array);
|
||||||
|
storage::serialization::write(writer, name + "/is_forward_edge", graph.is_forward_edge);
|
||||||
|
storage::serialization::write(writer, name + "/is_backward_edge", graph.is_backward_edge);
|
||||||
|
storage::serialization::write(writer, name + "/node_to_edge_offset", graph.node_to_edge_offset);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -50,6 +50,9 @@ template <typename AlgorithmT> struct HasMapMatching final : std::false_type
|
|||||||
template <typename AlgorithmT> struct HasManyToManySearch final : std::false_type
|
template <typename AlgorithmT> struct HasManyToManySearch final : std::false_type
|
||||||
{
|
{
|
||||||
};
|
};
|
||||||
|
template <typename AlgorithmT> struct SupportsDistanceAnnotationType final : std::false_type
|
||||||
|
{
|
||||||
|
};
|
||||||
template <typename AlgorithmT> struct HasGetTileTurns final : std::false_type
|
template <typename AlgorithmT> struct HasGetTileTurns final : std::false_type
|
||||||
{
|
{
|
||||||
};
|
};
|
||||||
@@ -73,6 +76,9 @@ template <> struct HasMapMatching<ch::Algorithm> final : std::true_type
|
|||||||
template <> struct HasManyToManySearch<ch::Algorithm> final : std::true_type
|
template <> struct HasManyToManySearch<ch::Algorithm> final : std::true_type
|
||||||
{
|
{
|
||||||
};
|
};
|
||||||
|
template <> struct SupportsDistanceAnnotationType<ch::Algorithm> final : std::true_type
|
||||||
|
{
|
||||||
|
};
|
||||||
template <> struct HasGetTileTurns<ch::Algorithm> final : std::true_type
|
template <> struct HasGetTileTurns<ch::Algorithm> final : std::true_type
|
||||||
{
|
{
|
||||||
};
|
};
|
||||||
@@ -96,6 +102,9 @@ template <> struct HasMapMatching<mld::Algorithm> final : std::true_type
|
|||||||
template <> struct HasManyToManySearch<mld::Algorithm> final : std::true_type
|
template <> struct HasManyToManySearch<mld::Algorithm> final : std::true_type
|
||||||
{
|
{
|
||||||
};
|
};
|
||||||
|
template <> struct SupportsDistanceAnnotationType<mld::Algorithm> final : std::false_type
|
||||||
|
{
|
||||||
|
};
|
||||||
template <> struct HasGetTileTurns<mld::Algorithm> final : std::true_type
|
template <> struct HasGetTileTurns<mld::Algorithm> final : std::true_type
|
||||||
{
|
{
|
||||||
};
|
};
|
||||||
|
|||||||
@@ -36,9 +36,10 @@ class TableAPI final : public BaseAPI
|
|||||||
{
|
{
|
||||||
}
|
}
|
||||||
|
|
||||||
virtual void MakeResponse(const std::vector<EdgeWeight> &durations,
|
virtual void
|
||||||
const std::vector<PhantomNode> &phantoms,
|
MakeResponse(const std::pair<std::vector<EdgeDuration>, std::vector<EdgeDistance>> &tables,
|
||||||
util::json::Object &response) const
|
const std::vector<PhantomNode> &phantoms,
|
||||||
|
util::json::Object &response) const
|
||||||
{
|
{
|
||||||
auto number_of_sources = parameters.sources.size();
|
auto number_of_sources = parameters.sources.size();
|
||||||
auto number_of_destinations = parameters.destinations.size();
|
auto number_of_destinations = parameters.destinations.size();
|
||||||
@@ -64,8 +65,18 @@ class TableAPI final : public BaseAPI
|
|||||||
response.values["destinations"] = MakeWaypoints(phantoms, parameters.destinations);
|
response.values["destinations"] = MakeWaypoints(phantoms, parameters.destinations);
|
||||||
}
|
}
|
||||||
|
|
||||||
response.values["durations"] =
|
if (parameters.annotations & TableParameters::AnnotationsType::Duration)
|
||||||
MakeTable(durations, number_of_sources, number_of_destinations);
|
{
|
||||||
|
response.values["durations"] =
|
||||||
|
MakeDurationTable(tables.first, number_of_sources, number_of_destinations);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (parameters.annotations & TableParameters::AnnotationsType::Distance)
|
||||||
|
{
|
||||||
|
response.values["distances"] =
|
||||||
|
MakeDistanceTable(tables.second, number_of_sources, number_of_destinations);
|
||||||
|
}
|
||||||
|
|
||||||
response.values["code"] = "Ok";
|
response.values["code"] = "Ok";
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -97,9 +108,9 @@ class TableAPI final : public BaseAPI
|
|||||||
return json_waypoints;
|
return json_waypoints;
|
||||||
}
|
}
|
||||||
|
|
||||||
virtual util::json::Array MakeTable(const std::vector<EdgeWeight> &values,
|
virtual util::json::Array MakeDurationTable(const std::vector<EdgeWeight> &values,
|
||||||
std::size_t number_of_rows,
|
std::size_t number_of_rows,
|
||||||
std::size_t number_of_columns) const
|
std::size_t number_of_columns) const
|
||||||
{
|
{
|
||||||
util::json::Array json_table;
|
util::json::Array json_table;
|
||||||
for (const auto row : util::irange<std::size_t>(0UL, number_of_rows))
|
for (const auto row : util::irange<std::size_t>(0UL, number_of_rows))
|
||||||
@@ -116,6 +127,7 @@ class TableAPI final : public BaseAPI
|
|||||||
{
|
{
|
||||||
return util::json::Value(util::json::Null());
|
return util::json::Value(util::json::Null());
|
||||||
}
|
}
|
||||||
|
// division by 10 because the duration is in deciseconds (10s)
|
||||||
return util::json::Value(util::json::Number(duration / 10.));
|
return util::json::Value(util::json::Number(duration / 10.));
|
||||||
});
|
});
|
||||||
json_table.values.push_back(std::move(json_row));
|
json_table.values.push_back(std::move(json_row));
|
||||||
@@ -123,6 +135,34 @@ class TableAPI final : public BaseAPI
|
|||||||
return json_table;
|
return json_table;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
virtual util::json::Array MakeDistanceTable(const std::vector<EdgeDistance> &values,
|
||||||
|
std::size_t number_of_rows,
|
||||||
|
std::size_t number_of_columns) const
|
||||||
|
{
|
||||||
|
util::json::Array json_table;
|
||||||
|
for (const auto row : util::irange<std::size_t>(0UL, number_of_rows))
|
||||||
|
{
|
||||||
|
util::json::Array json_row;
|
||||||
|
auto row_begin_iterator = values.begin() + (row * number_of_columns);
|
||||||
|
auto row_end_iterator = values.begin() + ((row + 1) * number_of_columns);
|
||||||
|
json_row.values.resize(number_of_columns);
|
||||||
|
std::transform(row_begin_iterator,
|
||||||
|
row_end_iterator,
|
||||||
|
json_row.values.begin(),
|
||||||
|
[](const EdgeDistance distance) {
|
||||||
|
if (distance == INVALID_EDGE_DISTANCE)
|
||||||
|
{
|
||||||
|
return util::json::Value(util::json::Null());
|
||||||
|
}
|
||||||
|
// round to single decimal place
|
||||||
|
return util::json::Value(
|
||||||
|
util::json::Number(std::round(distance * 10) / 10.));
|
||||||
|
});
|
||||||
|
json_table.values.push_back(std::move(json_row));
|
||||||
|
}
|
||||||
|
return json_table;
|
||||||
|
}
|
||||||
|
|
||||||
const TableParameters ¶meters;
|
const TableParameters ¶meters;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|||||||
@@ -60,6 +60,16 @@ struct TableParameters : public BaseParameters
|
|||||||
std::vector<std::size_t> sources;
|
std::vector<std::size_t> sources;
|
||||||
std::vector<std::size_t> destinations;
|
std::vector<std::size_t> destinations;
|
||||||
|
|
||||||
|
enum class AnnotationsType
|
||||||
|
{
|
||||||
|
None = 0,
|
||||||
|
Duration = 0x01,
|
||||||
|
Distance = 0x02,
|
||||||
|
All = Duration | Distance
|
||||||
|
};
|
||||||
|
|
||||||
|
AnnotationsType annotations = AnnotationsType::Duration;
|
||||||
|
|
||||||
TableParameters() = default;
|
TableParameters() = default;
|
||||||
template <typename... Args>
|
template <typename... Args>
|
||||||
TableParameters(std::vector<std::size_t> sources_,
|
TableParameters(std::vector<std::size_t> sources_,
|
||||||
@@ -70,6 +80,16 @@ struct TableParameters : public BaseParameters
|
|||||||
{
|
{
|
||||||
}
|
}
|
||||||
|
|
||||||
|
template <typename... Args>
|
||||||
|
TableParameters(std::vector<std::size_t> sources_,
|
||||||
|
std::vector<std::size_t> destinations_,
|
||||||
|
const AnnotationsType annotations_,
|
||||||
|
Args... args_)
|
||||||
|
: BaseParameters{std::forward<Args>(args_)...}, sources{std::move(sources_)},
|
||||||
|
destinations{std::move(destinations_)}, annotations{annotations_}
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
bool IsValid() const
|
bool IsValid() const
|
||||||
{
|
{
|
||||||
if (!BaseParameters::IsValid())
|
if (!BaseParameters::IsValid())
|
||||||
@@ -79,7 +99,7 @@ struct TableParameters : public BaseParameters
|
|||||||
if (coordinates.size() < 2)
|
if (coordinates.size() < 2)
|
||||||
return false;
|
return false;
|
||||||
|
|
||||||
// 1/ The user is able to specify duplicates in srcs and dsts, in that case it's her fault
|
// 1/ The user is able to specify duplicates in srcs and dsts, in that case it's their fault
|
||||||
|
|
||||||
// 2/ len(srcs) and len(dsts) smaller or equal to len(locations)
|
// 2/ len(srcs) and len(dsts) smaller or equal to len(locations)
|
||||||
if (sources.size() > coordinates.size())
|
if (sources.size() > coordinates.size())
|
||||||
@@ -100,6 +120,26 @@ struct TableParameters : public BaseParameters
|
|||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
inline bool operator&(TableParameters::AnnotationsType lhs, TableParameters::AnnotationsType rhs)
|
||||||
|
{
|
||||||
|
return static_cast<bool>(
|
||||||
|
static_cast<std::underlying_type_t<TableParameters::AnnotationsType>>(lhs) &
|
||||||
|
static_cast<std::underlying_type_t<TableParameters::AnnotationsType>>(rhs));
|
||||||
|
}
|
||||||
|
|
||||||
|
inline TableParameters::AnnotationsType operator|(TableParameters::AnnotationsType lhs,
|
||||||
|
TableParameters::AnnotationsType rhs)
|
||||||
|
{
|
||||||
|
return (TableParameters::AnnotationsType)(
|
||||||
|
static_cast<std::underlying_type_t<TableParameters::AnnotationsType>>(lhs) |
|
||||||
|
static_cast<std::underlying_type_t<TableParameters::AnnotationsType>>(rhs));
|
||||||
|
}
|
||||||
|
|
||||||
|
inline TableParameters::AnnotationsType &operator|=(TableParameters::AnnotationsType &lhs,
|
||||||
|
TableParameters::AnnotationsType rhs)
|
||||||
|
{
|
||||||
|
return lhs = lhs | rhs;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -2,6 +2,7 @@
|
|||||||
#define OSRM_ENGINE_DATAFACADE_ALGORITHM_DATAFACADE_HPP
|
#define OSRM_ENGINE_DATAFACADE_ALGORITHM_DATAFACADE_HPP
|
||||||
|
|
||||||
#include "contractor/query_edge.hpp"
|
#include "contractor/query_edge.hpp"
|
||||||
|
#include "customizer/edge_based_graph.hpp"
|
||||||
#include "extractor/edge_based_edge.hpp"
|
#include "extractor/edge_based_edge.hpp"
|
||||||
#include "engine/algorithm.hpp"
|
#include "engine/algorithm.hpp"
|
||||||
|
|
||||||
@@ -59,7 +60,7 @@ template <> class AlgorithmDataFacade<CH>
|
|||||||
template <> class AlgorithmDataFacade<MLD>
|
template <> class AlgorithmDataFacade<MLD>
|
||||||
{
|
{
|
||||||
public:
|
public:
|
||||||
using EdgeData = extractor::EdgeBasedEdge::EdgeData;
|
using EdgeData = customizer::EdgeBasedGraphEdgeData;
|
||||||
using EdgeRange = util::range<EdgeID>;
|
using EdgeRange = util::range<EdgeID>;
|
||||||
|
|
||||||
// search graph access
|
// search graph access
|
||||||
@@ -71,12 +72,20 @@ template <> class AlgorithmDataFacade<MLD>
|
|||||||
|
|
||||||
virtual unsigned GetOutDegree(const NodeID n) const = 0;
|
virtual unsigned GetOutDegree(const NodeID n) const = 0;
|
||||||
|
|
||||||
|
virtual EdgeRange GetAdjacentEdgeRange(const NodeID node) const = 0;
|
||||||
|
|
||||||
|
virtual EdgeWeight GetNodeWeight(const NodeID node) const = 0;
|
||||||
|
|
||||||
|
virtual EdgeWeight GetNodeDuration(const NodeID node) const = 0; // TODO: to be removed
|
||||||
|
|
||||||
|
virtual bool IsForwardEdge(EdgeID edge) const = 0;
|
||||||
|
|
||||||
|
virtual bool IsBackwardEdge(EdgeID edge) const = 0;
|
||||||
|
|
||||||
virtual NodeID GetTarget(const EdgeID e) const = 0;
|
virtual NodeID GetTarget(const EdgeID e) const = 0;
|
||||||
|
|
||||||
virtual const EdgeData &GetEdgeData(const EdgeID e) const = 0;
|
virtual const EdgeData &GetEdgeData(const EdgeID e) const = 0;
|
||||||
|
|
||||||
virtual EdgeRange GetAdjacentEdgeRange(const NodeID node) const = 0;
|
|
||||||
|
|
||||||
virtual const partitioner::MultiLevelPartitionView &GetMultiLevelPartition() const = 0;
|
virtual const partitioner::MultiLevelPartitionView &GetMultiLevelPartition() const = 0;
|
||||||
|
|
||||||
virtual const partitioner::CellStorageView &GetCellStorage() const = 0;
|
virtual const partitioner::CellStorageView &GetCellStorage() const = 0;
|
||||||
|
|||||||
@@ -133,7 +133,6 @@ class ContiguousInternalMemoryDataFacadeBase : public BaseDataFacade
|
|||||||
using RTreeNode = SharedRTree::TreeNode;
|
using RTreeNode = SharedRTree::TreeNode;
|
||||||
|
|
||||||
extractor::ClassData exclude_mask;
|
extractor::ClassData exclude_mask;
|
||||||
std::string m_timestamp;
|
|
||||||
extractor::ProfileProperties *m_profile_properties;
|
extractor::ProfileProperties *m_profile_properties;
|
||||||
extractor::Datasources *m_datasources;
|
extractor::Datasources *m_datasources;
|
||||||
|
|
||||||
@@ -283,13 +282,13 @@ class ContiguousInternalMemoryDataFacadeBase : public BaseDataFacade
|
|||||||
return segment_data.GetReverseDatasources(id);
|
return segment_data.GetReverseDatasources(id);
|
||||||
}
|
}
|
||||||
|
|
||||||
TurnPenalty GetWeightPenaltyForEdgeID(const unsigned id) const override final
|
TurnPenalty GetWeightPenaltyForEdgeID(const EdgeID id) const override final
|
||||||
{
|
{
|
||||||
BOOST_ASSERT(m_turn_weight_penalties.size() > id);
|
BOOST_ASSERT(m_turn_weight_penalties.size() > id);
|
||||||
return m_turn_weight_penalties[id];
|
return m_turn_weight_penalties[id];
|
||||||
}
|
}
|
||||||
|
|
||||||
TurnPenalty GetDurationPenaltyForEdgeID(const unsigned id) const override final
|
TurnPenalty GetDurationPenaltyForEdgeID(const EdgeID id) const override final
|
||||||
{
|
{
|
||||||
BOOST_ASSERT(m_turn_duration_penalties.size() > id);
|
BOOST_ASSERT(m_turn_duration_penalties.size() > id);
|
||||||
return m_turn_duration_penalties[id];
|
return m_turn_duration_penalties[id];
|
||||||
@@ -622,7 +621,6 @@ class ContiguousInternalMemoryDataFacade<CH>
|
|||||||
const std::size_t exclude_index)
|
const std::size_t exclude_index)
|
||||||
: ContiguousInternalMemoryDataFacadeBase(allocator, metric_name, exclude_index),
|
: ContiguousInternalMemoryDataFacadeBase(allocator, metric_name, exclude_index),
|
||||||
ContiguousInternalMemoryAlgorithmDataFacade<CH>(allocator, metric_name, exclude_index)
|
ContiguousInternalMemoryAlgorithmDataFacade<CH>(allocator, metric_name, exclude_index)
|
||||||
|
|
||||||
{
|
{
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
@@ -684,6 +682,31 @@ template <> class ContiguousInternalMemoryAlgorithmDataFacade<MLD> : public Algo
|
|||||||
return query_graph.GetOutDegree(n);
|
return query_graph.GetOutDegree(n);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
EdgeRange GetAdjacentEdgeRange(const NodeID node) const override final
|
||||||
|
{
|
||||||
|
return query_graph.GetAdjacentEdgeRange(node);
|
||||||
|
}
|
||||||
|
|
||||||
|
EdgeWeight GetNodeWeight(const NodeID node) const override final
|
||||||
|
{
|
||||||
|
return query_graph.GetNodeWeight(node);
|
||||||
|
}
|
||||||
|
|
||||||
|
EdgeDuration GetNodeDuration(const NodeID node) const override final
|
||||||
|
{
|
||||||
|
return query_graph.GetNodeDuration(node);
|
||||||
|
}
|
||||||
|
|
||||||
|
bool IsForwardEdge(const NodeID node) const override final
|
||||||
|
{
|
||||||
|
return query_graph.IsForwardEdge(node);
|
||||||
|
}
|
||||||
|
|
||||||
|
bool IsBackwardEdge(const NodeID node) const override final
|
||||||
|
{
|
||||||
|
return query_graph.IsBackwardEdge(node);
|
||||||
|
}
|
||||||
|
|
||||||
NodeID GetTarget(const EdgeID e) const override final { return query_graph.GetTarget(e); }
|
NodeID GetTarget(const EdgeID e) const override final { return query_graph.GetTarget(e); }
|
||||||
|
|
||||||
const EdgeData &GetEdgeData(const EdgeID e) const override final
|
const EdgeData &GetEdgeData(const EdgeID e) const override final
|
||||||
@@ -691,11 +714,6 @@ template <> class ContiguousInternalMemoryAlgorithmDataFacade<MLD> : public Algo
|
|||||||
return query_graph.GetEdgeData(e);
|
return query_graph.GetEdgeData(e);
|
||||||
}
|
}
|
||||||
|
|
||||||
EdgeRange GetAdjacentEdgeRange(const NodeID node) const override final
|
|
||||||
{
|
|
||||||
return query_graph.GetAdjacentEdgeRange(node);
|
|
||||||
}
|
|
||||||
|
|
||||||
EdgeRange GetBorderEdgeRange(const LevelID level, const NodeID node) const override final
|
EdgeRange GetBorderEdgeRange(const LevelID level, const NodeID node) const override final
|
||||||
{
|
{
|
||||||
return query_graph.GetBorderEdgeRange(level, node);
|
return query_graph.GetBorderEdgeRange(level, node);
|
||||||
@@ -720,7 +738,6 @@ class ContiguousInternalMemoryDataFacade<MLD> final
|
|||||||
const std::size_t exclude_index)
|
const std::size_t exclude_index)
|
||||||
: ContiguousInternalMemoryDataFacadeBase(allocator, metric_name, exclude_index),
|
: ContiguousInternalMemoryDataFacadeBase(allocator, metric_name, exclude_index),
|
||||||
ContiguousInternalMemoryAlgorithmDataFacade<MLD>(allocator, metric_name, exclude_index)
|
ContiguousInternalMemoryAlgorithmDataFacade<MLD>(allocator, metric_name, exclude_index)
|
||||||
|
|
||||||
{
|
{
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|||||||
@@ -33,7 +33,6 @@
|
|||||||
|
|
||||||
#include <boost/range/adaptor/reversed.hpp>
|
#include <boost/range/adaptor/reversed.hpp>
|
||||||
#include <boost/range/any_range.hpp>
|
#include <boost/range/any_range.hpp>
|
||||||
|
|
||||||
#include <cstddef>
|
#include <cstddef>
|
||||||
|
|
||||||
#include <string>
|
#include <string>
|
||||||
@@ -87,9 +86,9 @@ class BaseDataFacade
|
|||||||
virtual NodeForwardRange GetUncompressedForwardGeometry(const EdgeID id) const = 0;
|
virtual NodeForwardRange GetUncompressedForwardGeometry(const EdgeID id) const = 0;
|
||||||
virtual NodeReverseRange GetUncompressedReverseGeometry(const EdgeID id) const = 0;
|
virtual NodeReverseRange GetUncompressedReverseGeometry(const EdgeID id) const = 0;
|
||||||
|
|
||||||
virtual TurnPenalty GetWeightPenaltyForEdgeID(const unsigned id) const = 0;
|
virtual TurnPenalty GetWeightPenaltyForEdgeID(const EdgeID id) const = 0;
|
||||||
|
|
||||||
virtual TurnPenalty GetDurationPenaltyForEdgeID(const unsigned id) const = 0;
|
virtual TurnPenalty GetDurationPenaltyForEdgeID(const EdgeID id) const = 0;
|
||||||
|
|
||||||
// Gets the weight values for each segment in an uncompressed geometry.
|
// Gets the weight values for each segment in an uncompressed geometry.
|
||||||
// Should always be 1 shorter than GetUncompressedGeometry
|
// Should always be 1 shorter than GetUncompressedGeometry
|
||||||
|
|||||||
@@ -13,6 +13,7 @@
|
|||||||
|
|
||||||
#include <algorithm>
|
#include <algorithm>
|
||||||
#include <cmath>
|
#include <cmath>
|
||||||
|
#include <iterator>
|
||||||
#include <memory>
|
#include <memory>
|
||||||
#include <vector>
|
#include <vector>
|
||||||
|
|
||||||
@@ -447,6 +448,9 @@ template <typename RTreeT, typename DataFacadeT> class GeospatialQuery
|
|||||||
const auto forward_durations = datafacade.GetUncompressedForwardDurations(geometry_id);
|
const auto forward_durations = datafacade.GetUncompressedForwardDurations(geometry_id);
|
||||||
const auto reverse_durations = datafacade.GetUncompressedReverseDurations(geometry_id);
|
const auto reverse_durations = datafacade.GetUncompressedReverseDurations(geometry_id);
|
||||||
|
|
||||||
|
const auto forward_geometry = datafacade.GetUncompressedForwardGeometry(geometry_id);
|
||||||
|
const auto reverse_geometry = datafacade.GetUncompressedReverseGeometry(geometry_id);
|
||||||
|
|
||||||
const auto forward_weight_offset =
|
const auto forward_weight_offset =
|
||||||
std::accumulate(forward_weights.begin(),
|
std::accumulate(forward_weights.begin(),
|
||||||
forward_weights.begin() + data.fwd_segment_position,
|
forward_weights.begin() + data.fwd_segment_position,
|
||||||
@@ -457,26 +461,50 @@ template <typename RTreeT, typename DataFacadeT> class GeospatialQuery
|
|||||||
forward_durations.begin() + data.fwd_segment_position,
|
forward_durations.begin() + data.fwd_segment_position,
|
||||||
EdgeDuration{0});
|
EdgeDuration{0});
|
||||||
|
|
||||||
EdgeWeight forward_weight = forward_weights[data.fwd_segment_position];
|
EdgeDistance forward_distance_offset = 0;
|
||||||
EdgeDuration forward_duration = forward_durations[data.fwd_segment_position];
|
for (auto current = forward_geometry.begin();
|
||||||
|
current < forward_geometry.begin() + data.fwd_segment_position;
|
||||||
|
++current)
|
||||||
|
{
|
||||||
|
forward_distance_offset += util::coordinate_calculation::fccApproximateDistance(
|
||||||
|
datafacade.GetCoordinateOfNode(*current),
|
||||||
|
datafacade.GetCoordinateOfNode(*std::next(current)));
|
||||||
|
}
|
||||||
|
|
||||||
BOOST_ASSERT(data.fwd_segment_position <
|
BOOST_ASSERT(data.fwd_segment_position <
|
||||||
std::distance(forward_durations.begin(), forward_durations.end()));
|
std::distance(forward_durations.begin(), forward_durations.end()));
|
||||||
|
|
||||||
const auto reverse_weight_offset =
|
EdgeWeight forward_weight = forward_weights[data.fwd_segment_position];
|
||||||
std::accumulate(reverse_weights.begin(),
|
EdgeDuration forward_duration = forward_durations[data.fwd_segment_position];
|
||||||
reverse_weights.end() - data.fwd_segment_position - 1,
|
EdgeDistance forward_distance = util::coordinate_calculation::fccApproximateDistance(
|
||||||
EdgeWeight{0});
|
datafacade.GetCoordinateOfNode(forward_geometry(data.fwd_segment_position)),
|
||||||
|
point_on_segment);
|
||||||
|
|
||||||
|
const auto rev_segment_position = reverse_weights.size() - data.fwd_segment_position - 1;
|
||||||
|
|
||||||
|
const auto reverse_weight_offset = std::accumulate(
|
||||||
|
reverse_weights.begin(), reverse_weights.begin() + rev_segment_position, EdgeWeight{0});
|
||||||
|
|
||||||
const auto reverse_duration_offset =
|
const auto reverse_duration_offset =
|
||||||
std::accumulate(reverse_durations.begin(),
|
std::accumulate(reverse_durations.begin(),
|
||||||
reverse_durations.end() - data.fwd_segment_position - 1,
|
reverse_durations.begin() + rev_segment_position,
|
||||||
EdgeDuration{0});
|
EdgeDuration{0});
|
||||||
|
|
||||||
EdgeWeight reverse_weight =
|
EdgeDistance reverse_distance_offset = 0;
|
||||||
reverse_weights[reverse_weights.size() - data.fwd_segment_position - 1];
|
for (auto current = reverse_geometry.begin();
|
||||||
EdgeDuration reverse_duration =
|
current < reverse_geometry.begin() + rev_segment_position;
|
||||||
reverse_durations[reverse_durations.size() - data.fwd_segment_position - 1];
|
++current)
|
||||||
|
{
|
||||||
|
reverse_distance_offset += util::coordinate_calculation::fccApproximateDistance(
|
||||||
|
datafacade.GetCoordinateOfNode(*current),
|
||||||
|
datafacade.GetCoordinateOfNode(*std::next(current)));
|
||||||
|
}
|
||||||
|
|
||||||
|
EdgeWeight reverse_weight = reverse_weights[rev_segment_position];
|
||||||
|
EdgeDuration reverse_duration = reverse_durations[rev_segment_position];
|
||||||
|
EdgeDistance reverse_distance = util::coordinate_calculation::fccApproximateDistance(
|
||||||
|
point_on_segment,
|
||||||
|
datafacade.GetCoordinateOfNode(reverse_geometry(rev_segment_position)));
|
||||||
|
|
||||||
ratio = std::min(1.0, std::max(0.0, ratio));
|
ratio = std::min(1.0, std::max(0.0, ratio));
|
||||||
if (data.forward_segment_id.id != SPECIAL_SEGMENTID)
|
if (data.forward_segment_id.id != SPECIAL_SEGMENTID)
|
||||||
@@ -510,6 +538,10 @@ template <typename RTreeT, typename DataFacadeT> class GeospatialQuery
|
|||||||
reverse_weight,
|
reverse_weight,
|
||||||
forward_weight_offset,
|
forward_weight_offset,
|
||||||
reverse_weight_offset,
|
reverse_weight_offset,
|
||||||
|
forward_distance,
|
||||||
|
reverse_distance,
|
||||||
|
forward_distance_offset,
|
||||||
|
reverse_distance_offset,
|
||||||
forward_duration,
|
forward_duration,
|
||||||
reverse_duration,
|
reverse_duration,
|
||||||
forward_duration_offset,
|
forward_duration_offset,
|
||||||
@@ -660,7 +692,7 @@ template <typename RTreeT, typename DataFacadeT> class GeospatialQuery
|
|||||||
const CoordinateList &coordinates;
|
const CoordinateList &coordinates;
|
||||||
DataFacadeT &datafacade;
|
DataFacadeT &datafacade;
|
||||||
};
|
};
|
||||||
}
|
} // namespace engine
|
||||||
}
|
} // namespace osrm
|
||||||
|
|
||||||
#endif
|
#endif
|
||||||
|
|||||||
@@ -63,8 +63,8 @@ struct Hint
|
|||||||
friend std::ostream &operator<<(std::ostream &, const Hint &);
|
friend std::ostream &operator<<(std::ostream &, const Hint &);
|
||||||
};
|
};
|
||||||
|
|
||||||
static_assert(sizeof(Hint) == 64 + 4, "Hint is bigger than expected");
|
static_assert(sizeof(Hint) == 80 + 4, "Hint is bigger than expected");
|
||||||
constexpr std::size_t ENCODED_HINT_SIZE = 92;
|
constexpr std::size_t ENCODED_HINT_SIZE = 112;
|
||||||
static_assert(ENCODED_HINT_SIZE / 4 * 3 >= sizeof(Hint),
|
static_assert(ENCODED_HINT_SIZE / 4 * 3 >= sizeof(Hint),
|
||||||
"ENCODED_HINT_SIZE does not match size of Hint");
|
"ENCODED_HINT_SIZE does not match size of Hint");
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -34,6 +34,8 @@ SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
|||||||
#include "util/coordinate.hpp"
|
#include "util/coordinate.hpp"
|
||||||
#include "util/typedefs.hpp"
|
#include "util/typedefs.hpp"
|
||||||
|
|
||||||
|
#include <iostream>
|
||||||
|
|
||||||
#include <boost/assert.hpp>
|
#include <boost/assert.hpp>
|
||||||
|
|
||||||
namespace osrm
|
namespace osrm
|
||||||
@@ -44,13 +46,17 @@ namespace engine
|
|||||||
struct PhantomNode
|
struct PhantomNode
|
||||||
{
|
{
|
||||||
PhantomNode()
|
PhantomNode()
|
||||||
: forward_segment_id{SPECIAL_SEGMENTID, false},
|
: forward_segment_id{SPECIAL_SEGMENTID, false}, reverse_segment_id{SPECIAL_SEGMENTID,
|
||||||
reverse_segment_id{SPECIAL_SEGMENTID, false}, forward_weight(INVALID_EDGE_WEIGHT),
|
false},
|
||||||
reverse_weight(INVALID_EDGE_WEIGHT), forward_weight_offset(0), reverse_weight_offset(0),
|
forward_weight(INVALID_EDGE_WEIGHT), reverse_weight(INVALID_EDGE_WEIGHT),
|
||||||
|
forward_weight_offset(0), reverse_weight_offset(0),
|
||||||
|
forward_distance(INVALID_EDGE_DISTANCE), reverse_distance(INVALID_EDGE_DISTANCE),
|
||||||
|
forward_distance_offset(0), reverse_distance_offset(0),
|
||||||
forward_duration(MAXIMAL_EDGE_DURATION), reverse_duration(MAXIMAL_EDGE_DURATION),
|
forward_duration(MAXIMAL_EDGE_DURATION), reverse_duration(MAXIMAL_EDGE_DURATION),
|
||||||
forward_duration_offset(0), reverse_duration_offset(0), fwd_segment_position(0),
|
forward_duration_offset(0), reverse_duration_offset(0),
|
||||||
is_valid_forward_source{false}, is_valid_forward_target{false},
|
fwd_segment_position(0), is_valid_forward_source{false}, is_valid_forward_target{false},
|
||||||
is_valid_reverse_source{false}, is_valid_reverse_target{false}, bearing(0)
|
is_valid_reverse_source{false}, is_valid_reverse_target{false}, bearing(0)
|
||||||
|
|
||||||
{
|
{
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -78,16 +84,43 @@ struct PhantomNode
|
|||||||
return reverse_duration + reverse_duration_offset;
|
return reverse_duration + reverse_duration_offset;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// DO THIS FOR DISTANCE
|
||||||
|
|
||||||
|
EdgeDistance GetForwardDistance() const
|
||||||
|
{
|
||||||
|
// ..... <-- forward_distance
|
||||||
|
// .... <-- offset
|
||||||
|
// ......... <-- desired distance
|
||||||
|
// x <-- this is PhantomNode.location
|
||||||
|
// 0----1----2----3----4 <-- EdgeBasedGraph Node segments
|
||||||
|
BOOST_ASSERT(forward_segment_id.enabled);
|
||||||
|
return forward_distance + forward_distance_offset;
|
||||||
|
}
|
||||||
|
|
||||||
|
EdgeDistance GetReverseDistance() const
|
||||||
|
{
|
||||||
|
// .......... <-- reverse_distance
|
||||||
|
// ... <-- offset
|
||||||
|
// ............. <-- desired distance
|
||||||
|
// x <-- this is PhantomNode.location
|
||||||
|
// 0----1----2----3----4 <-- EdgeBasedGraph Node segments
|
||||||
|
BOOST_ASSERT(reverse_segment_id.enabled);
|
||||||
|
return reverse_distance + reverse_distance_offset;
|
||||||
|
}
|
||||||
|
|
||||||
bool IsBidirected() const { return forward_segment_id.enabled && reverse_segment_id.enabled; }
|
bool IsBidirected() const { return forward_segment_id.enabled && reverse_segment_id.enabled; }
|
||||||
|
|
||||||
bool IsValid(const unsigned number_of_nodes) const
|
bool IsValid(const unsigned number_of_nodes) const
|
||||||
{
|
{
|
||||||
return location.IsValid() && ((forward_segment_id.id < number_of_nodes) ||
|
return location.IsValid() &&
|
||||||
(reverse_segment_id.id < number_of_nodes)) &&
|
((forward_segment_id.id < number_of_nodes) ||
|
||||||
|
(reverse_segment_id.id < number_of_nodes)) &&
|
||||||
((forward_weight != INVALID_EDGE_WEIGHT) ||
|
((forward_weight != INVALID_EDGE_WEIGHT) ||
|
||||||
(reverse_weight != INVALID_EDGE_WEIGHT)) &&
|
(reverse_weight != INVALID_EDGE_WEIGHT)) &&
|
||||||
((forward_duration != MAXIMAL_EDGE_DURATION) ||
|
((forward_duration != MAXIMAL_EDGE_DURATION) ||
|
||||||
(reverse_duration != MAXIMAL_EDGE_DURATION)) &&
|
(reverse_duration != MAXIMAL_EDGE_DURATION)) &&
|
||||||
|
((forward_distance != INVALID_EDGE_DISTANCE) ||
|
||||||
|
(reverse_distance != INVALID_EDGE_DISTANCE)) &&
|
||||||
(component.id != INVALID_COMPONENTID);
|
(component.id != INVALID_COMPONENTID);
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -130,6 +163,10 @@ struct PhantomNode
|
|||||||
EdgeWeight reverse_weight,
|
EdgeWeight reverse_weight,
|
||||||
EdgeWeight forward_weight_offset,
|
EdgeWeight forward_weight_offset,
|
||||||
EdgeWeight reverse_weight_offset,
|
EdgeWeight reverse_weight_offset,
|
||||||
|
EdgeDistance forward_distance,
|
||||||
|
EdgeDistance reverse_distance,
|
||||||
|
EdgeDistance forward_distance_offset,
|
||||||
|
EdgeDistance reverse_distance_offset,
|
||||||
EdgeWeight forward_duration,
|
EdgeWeight forward_duration,
|
||||||
EdgeWeight reverse_duration,
|
EdgeWeight reverse_duration,
|
||||||
EdgeWeight forward_duration_offset,
|
EdgeWeight forward_duration_offset,
|
||||||
@@ -144,7 +181,9 @@ struct PhantomNode
|
|||||||
: forward_segment_id{other.forward_segment_id},
|
: forward_segment_id{other.forward_segment_id},
|
||||||
reverse_segment_id{other.reverse_segment_id}, forward_weight{forward_weight},
|
reverse_segment_id{other.reverse_segment_id}, forward_weight{forward_weight},
|
||||||
reverse_weight{reverse_weight}, forward_weight_offset{forward_weight_offset},
|
reverse_weight{reverse_weight}, forward_weight_offset{forward_weight_offset},
|
||||||
reverse_weight_offset{reverse_weight_offset}, forward_duration{forward_duration},
|
reverse_weight_offset{reverse_weight_offset}, forward_distance{forward_distance},
|
||||||
|
reverse_distance{reverse_distance}, forward_distance_offset{forward_distance_offset},
|
||||||
|
reverse_distance_offset{reverse_distance_offset}, forward_duration{forward_duration},
|
||||||
reverse_duration{reverse_duration}, forward_duration_offset{forward_duration_offset},
|
reverse_duration{reverse_duration}, forward_duration_offset{forward_duration_offset},
|
||||||
reverse_duration_offset{reverse_duration_offset},
|
reverse_duration_offset{reverse_duration_offset},
|
||||||
component{component.id, component.is_tiny}, location{location},
|
component{component.id, component.is_tiny}, location{location},
|
||||||
@@ -162,13 +201,17 @@ struct PhantomNode
|
|||||||
EdgeWeight reverse_weight;
|
EdgeWeight reverse_weight;
|
||||||
EdgeWeight forward_weight_offset; // TODO: try to remove -> requires path unpacking changes
|
EdgeWeight forward_weight_offset; // TODO: try to remove -> requires path unpacking changes
|
||||||
EdgeWeight reverse_weight_offset; // TODO: try to remove -> requires path unpacking changes
|
EdgeWeight reverse_weight_offset; // TODO: try to remove -> requires path unpacking changes
|
||||||
|
EdgeDistance forward_distance;
|
||||||
|
EdgeDistance reverse_distance;
|
||||||
|
EdgeDistance forward_distance_offset; // TODO: try to remove -> requires path unpacking changes
|
||||||
|
EdgeDistance reverse_distance_offset; // TODO: try to remove -> requires path unpacking changes
|
||||||
EdgeWeight forward_duration;
|
EdgeWeight forward_duration;
|
||||||
EdgeWeight reverse_duration;
|
EdgeWeight reverse_duration;
|
||||||
EdgeWeight forward_duration_offset; // TODO: try to remove -> requires path unpacking changes
|
EdgeWeight forward_duration_offset; // TODO: try to remove -> requires path unpacking changes
|
||||||
EdgeWeight reverse_duration_offset; // TODO: try to remove -> requires path unpacking changes
|
EdgeWeight reverse_duration_offset; // TODO: try to remove -> requires path unpacking changes
|
||||||
ComponentID component;
|
ComponentID component;
|
||||||
|
|
||||||
util::Coordinate location;
|
util::Coordinate location; // this is the coordinate of x
|
||||||
util::Coordinate input_location;
|
util::Coordinate input_location;
|
||||||
unsigned short fwd_segment_position;
|
unsigned short fwd_segment_position;
|
||||||
// is phantom node valid to be used as source or target
|
// is phantom node valid to be used as source or target
|
||||||
@@ -180,7 +223,7 @@ struct PhantomNode
|
|||||||
unsigned short bearing : 12;
|
unsigned short bearing : 12;
|
||||||
};
|
};
|
||||||
|
|
||||||
static_assert(sizeof(PhantomNode) == 64, "PhantomNode has more padding then expected");
|
static_assert(sizeof(PhantomNode) == 80, "PhantomNode has more padding then expected");
|
||||||
|
|
||||||
using PhantomNodePair = std::pair<PhantomNode, PhantomNode>;
|
using PhantomNodePair = std::pair<PhantomNode, PhantomNode>;
|
||||||
|
|
||||||
@@ -195,7 +238,7 @@ struct PhantomNodes
|
|||||||
PhantomNode source_phantom;
|
PhantomNode source_phantom;
|
||||||
PhantomNode target_phantom;
|
PhantomNode target_phantom;
|
||||||
};
|
};
|
||||||
}
|
} // namespace engine
|
||||||
}
|
} // namespace osrm
|
||||||
|
|
||||||
#endif // PHANTOM_NODES_H
|
#endif // PHANTOM_NODES_H
|
||||||
|
|||||||
@@ -30,10 +30,12 @@ class RoutingAlgorithmsInterface
|
|||||||
virtual InternalRouteResult
|
virtual InternalRouteResult
|
||||||
DirectShortestPathSearch(const PhantomNodes &phantom_node_pair) const = 0;
|
DirectShortestPathSearch(const PhantomNodes &phantom_node_pair) const = 0;
|
||||||
|
|
||||||
virtual std::vector<EdgeDuration>
|
virtual std::pair<std::vector<EdgeDuration>, std::vector<EdgeDistance>>
|
||||||
ManyToManySearch(const std::vector<PhantomNode> &phantom_nodes,
|
ManyToManySearch(const std::vector<PhantomNode> &phantom_nodes,
|
||||||
const std::vector<std::size_t> &source_indices,
|
const std::vector<std::size_t> &source_indices,
|
||||||
const std::vector<std::size_t> &target_indices) const = 0;
|
const std::vector<std::size_t> &target_indices,
|
||||||
|
const bool calculate_distance,
|
||||||
|
const bool calculate_duration) const = 0;
|
||||||
|
|
||||||
virtual routing_algorithms::SubMatchingList
|
virtual routing_algorithms::SubMatchingList
|
||||||
MapMatching(const routing_algorithms::CandidateLists &candidates_list,
|
MapMatching(const routing_algorithms::CandidateLists &candidates_list,
|
||||||
@@ -53,6 +55,7 @@ class RoutingAlgorithmsInterface
|
|||||||
virtual bool HasDirectShortestPathSearch() const = 0;
|
virtual bool HasDirectShortestPathSearch() const = 0;
|
||||||
virtual bool HasMapMatching() const = 0;
|
virtual bool HasMapMatching() const = 0;
|
||||||
virtual bool HasManyToManySearch() const = 0;
|
virtual bool HasManyToManySearch() const = 0;
|
||||||
|
virtual bool SupportsDistanceAnnotationType() const = 0;
|
||||||
virtual bool HasGetTileTurns() const = 0;
|
virtual bool HasGetTileTurns() const = 0;
|
||||||
virtual bool HasExcludeFlags() const = 0;
|
virtual bool HasExcludeFlags() const = 0;
|
||||||
virtual bool IsValid() const = 0;
|
virtual bool IsValid() const = 0;
|
||||||
@@ -81,10 +84,12 @@ template <typename Algorithm> class RoutingAlgorithms final : public RoutingAlgo
|
|||||||
InternalRouteResult
|
InternalRouteResult
|
||||||
DirectShortestPathSearch(const PhantomNodes &phantom_nodes) const final override;
|
DirectShortestPathSearch(const PhantomNodes &phantom_nodes) const final override;
|
||||||
|
|
||||||
std::vector<EdgeDuration>
|
virtual std::pair<std::vector<EdgeDuration>, std::vector<EdgeDistance>>
|
||||||
ManyToManySearch(const std::vector<PhantomNode> &phantom_nodes,
|
ManyToManySearch(const std::vector<PhantomNode> &phantom_nodes,
|
||||||
const std::vector<std::size_t> &source_indices,
|
const std::vector<std::size_t> &source_indices,
|
||||||
const std::vector<std::size_t> &target_indices) const final override;
|
const std::vector<std::size_t> &target_indices,
|
||||||
|
const bool calculate_distance,
|
||||||
|
const bool calculate_duration) const final override;
|
||||||
|
|
||||||
routing_algorithms::SubMatchingList
|
routing_algorithms::SubMatchingList
|
||||||
MapMatching(const routing_algorithms::CandidateLists &candidates_list,
|
MapMatching(const routing_algorithms::CandidateLists &candidates_list,
|
||||||
@@ -124,6 +129,11 @@ template <typename Algorithm> class RoutingAlgorithms final : public RoutingAlgo
|
|||||||
return routing_algorithms::HasManyToManySearch<Algorithm>::value;
|
return routing_algorithms::HasManyToManySearch<Algorithm>::value;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
bool SupportsDistanceAnnotationType() const final override
|
||||||
|
{
|
||||||
|
return routing_algorithms::SupportsDistanceAnnotationType<Algorithm>::value;
|
||||||
|
}
|
||||||
|
|
||||||
bool HasGetTileTurns() const final override
|
bool HasGetTileTurns() const final override
|
||||||
{
|
{
|
||||||
return routing_algorithms::HasGetTileTurns<Algorithm>::value;
|
return routing_algorithms::HasGetTileTurns<Algorithm>::value;
|
||||||
@@ -184,10 +194,12 @@ inline routing_algorithms::SubMatchingList RoutingAlgorithms<Algorithm>::MapMatc
|
|||||||
}
|
}
|
||||||
|
|
||||||
template <typename Algorithm>
|
template <typename Algorithm>
|
||||||
std::vector<EdgeDuration> RoutingAlgorithms<Algorithm>::ManyToManySearch(
|
std::pair<std::vector<EdgeDuration>, std::vector<EdgeDistance>>
|
||||||
const std::vector<PhantomNode> &phantom_nodes,
|
RoutingAlgorithms<Algorithm>::ManyToManySearch(const std::vector<PhantomNode> &phantom_nodes,
|
||||||
const std::vector<std::size_t> &_source_indices,
|
const std::vector<std::size_t> &_source_indices,
|
||||||
const std::vector<std::size_t> &_target_indices) const
|
const std::vector<std::size_t> &_target_indices,
|
||||||
|
const bool calculate_distance,
|
||||||
|
const bool calculate_duration) const
|
||||||
{
|
{
|
||||||
BOOST_ASSERT(!phantom_nodes.empty());
|
BOOST_ASSERT(!phantom_nodes.empty());
|
||||||
|
|
||||||
@@ -205,8 +217,13 @@ std::vector<EdgeDuration> RoutingAlgorithms<Algorithm>::ManyToManySearch(
|
|||||||
std::iota(target_indices.begin(), target_indices.end(), 0);
|
std::iota(target_indices.begin(), target_indices.end(), 0);
|
||||||
}
|
}
|
||||||
|
|
||||||
return routing_algorithms::manyToManySearch(
|
return routing_algorithms::manyToManySearch(heaps,
|
||||||
heaps, *facade, phantom_nodes, std::move(source_indices), std::move(target_indices));
|
*facade,
|
||||||
|
phantom_nodes,
|
||||||
|
std::move(source_indices),
|
||||||
|
std::move(target_indices),
|
||||||
|
calculate_distance,
|
||||||
|
calculate_duration);
|
||||||
}
|
}
|
||||||
|
|
||||||
template <typename Algorithm>
|
template <typename Algorithm>
|
||||||
|
|||||||
@@ -15,23 +15,46 @@ namespace engine
|
|||||||
{
|
{
|
||||||
namespace routing_algorithms
|
namespace routing_algorithms
|
||||||
{
|
{
|
||||||
|
|
||||||
namespace
|
namespace
|
||||||
{
|
{
|
||||||
struct NodeBucket
|
struct NodeBucket
|
||||||
{
|
{
|
||||||
NodeID middle_node;
|
NodeID middle_node;
|
||||||
unsigned column_index; // a column in the weight/duration matrix
|
NodeID parent_node;
|
||||||
|
unsigned column_index : 31; // a column in the weight/duration matrix
|
||||||
|
unsigned from_clique_arc : 1;
|
||||||
EdgeWeight weight;
|
EdgeWeight weight;
|
||||||
EdgeDuration duration;
|
EdgeDuration duration;
|
||||||
|
EdgeDistance distance;
|
||||||
|
|
||||||
NodeBucket(NodeID middle_node, unsigned column_index, EdgeWeight weight, EdgeDuration duration)
|
NodeBucket(NodeID middle_node,
|
||||||
: middle_node(middle_node), column_index(column_index), weight(weight), duration(duration)
|
NodeID parent_node,
|
||||||
|
bool from_clique_arc,
|
||||||
|
unsigned column_index,
|
||||||
|
EdgeWeight weight,
|
||||||
|
EdgeDuration duration,
|
||||||
|
EdgeDistance distance)
|
||||||
|
: middle_node(middle_node), parent_node(parent_node), column_index(column_index),
|
||||||
|
from_clique_arc(from_clique_arc), weight(weight), duration(duration), distance(distance)
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
|
NodeBucket(NodeID middle_node,
|
||||||
|
NodeID parent_node,
|
||||||
|
unsigned column_index,
|
||||||
|
EdgeWeight weight,
|
||||||
|
EdgeDuration duration,
|
||||||
|
EdgeDistance distance)
|
||||||
|
: middle_node(middle_node), parent_node(parent_node), column_index(column_index),
|
||||||
|
from_clique_arc(false), weight(weight), duration(duration), distance(distance)
|
||||||
{
|
{
|
||||||
}
|
}
|
||||||
|
|
||||||
// partial order comparison
|
// partial order comparison
|
||||||
bool operator<(const NodeBucket &rhs) const { return middle_node < rhs.middle_node; }
|
bool operator<(const NodeBucket &rhs) const
|
||||||
|
{
|
||||||
|
return std::tie(middle_node, column_index) < std::tie(rhs.middle_node, rhs.column_index);
|
||||||
|
}
|
||||||
|
|
||||||
// functor for equal_range
|
// functor for equal_range
|
||||||
struct Compare
|
struct Compare
|
||||||
@@ -46,15 +69,36 @@ struct NodeBucket
|
|||||||
return lhs < rhs.middle_node;
|
return lhs < rhs.middle_node;
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
|
// functor for equal_range
|
||||||
|
struct ColumnCompare
|
||||||
|
{
|
||||||
|
unsigned column_idx;
|
||||||
|
|
||||||
|
ColumnCompare(unsigned column_idx) : column_idx(column_idx){};
|
||||||
|
|
||||||
|
bool operator()(const NodeBucket &lhs, const NodeID &rhs) const // lowerbound
|
||||||
|
{
|
||||||
|
return std::tie(lhs.middle_node, lhs.column_index) < std::tie(rhs, column_idx);
|
||||||
|
}
|
||||||
|
|
||||||
|
bool operator()(const NodeID &lhs, const NodeBucket &rhs) const // upperbound
|
||||||
|
{
|
||||||
|
return std::tie(lhs, column_idx) < std::tie(rhs.middle_node, rhs.column_index);
|
||||||
|
}
|
||||||
|
};
|
||||||
};
|
};
|
||||||
}
|
} // namespace
|
||||||
|
|
||||||
template <typename Algorithm>
|
template <typename Algorithm>
|
||||||
std::vector<EdgeDuration> manyToManySearch(SearchEngineData<Algorithm> &engine_working_data,
|
std::pair<std::vector<EdgeDuration>, std::vector<EdgeDistance>>
|
||||||
const DataFacade<Algorithm> &facade,
|
manyToManySearch(SearchEngineData<Algorithm> &engine_working_data,
|
||||||
const std::vector<PhantomNode> &phantom_nodes,
|
const DataFacade<Algorithm> &facade,
|
||||||
const std::vector<std::size_t> &source_indices,
|
const std::vector<PhantomNode> &phantom_nodes,
|
||||||
const std::vector<std::size_t> &target_indices);
|
const std::vector<std::size_t> &source_indices,
|
||||||
|
const std::vector<std::size_t> &target_indices,
|
||||||
|
const bool calculate_distance,
|
||||||
|
const bool calculate_duration);
|
||||||
|
|
||||||
} // namespace routing_algorithms
|
} // namespace routing_algorithms
|
||||||
} // namespace engine
|
} // namespace engine
|
||||||
|
|||||||
@@ -44,42 +44,140 @@ bool needsLoopBackwards(const PhantomNode &source_phantom, const PhantomNode &ta
|
|||||||
bool needsLoopForward(const PhantomNodes &phantoms);
|
bool needsLoopForward(const PhantomNodes &phantoms);
|
||||||
bool needsLoopBackwards(const PhantomNodes &phantoms);
|
bool needsLoopBackwards(const PhantomNodes &phantoms);
|
||||||
|
|
||||||
template <typename Heap>
|
namespace detail
|
||||||
void insertNodesInHeaps(Heap &forward_heap, Heap &reverse_heap, const PhantomNodes &nodes)
|
|
||||||
{
|
{
|
||||||
const auto &source = nodes.source_phantom;
|
template <typename Algorithm>
|
||||||
if (source.IsValidForwardSource())
|
void insertSourceInHeap(typename SearchEngineData<Algorithm>::ManyToManyQueryHeap &heap,
|
||||||
|
const PhantomNode &phantom_node)
|
||||||
|
{
|
||||||
|
if (phantom_node.IsValidForwardTarget())
|
||||||
{
|
{
|
||||||
forward_heap.Insert(source.forward_segment_id.id,
|
heap.Insert(phantom_node.forward_segment_id.id,
|
||||||
-source.GetForwardWeightPlusOffset(),
|
-phantom_node.GetForwardWeightPlusOffset(),
|
||||||
source.forward_segment_id.id);
|
{phantom_node.forward_segment_id.id,
|
||||||
|
-phantom_node.GetForwardDuration(),
|
||||||
|
-phantom_node.GetForwardDistance()});
|
||||||
}
|
}
|
||||||
|
if (phantom_node.IsValidReverseTarget())
|
||||||
if (source.IsValidReverseSource())
|
|
||||||
{
|
{
|
||||||
forward_heap.Insert(source.reverse_segment_id.id,
|
heap.Insert(phantom_node.reverse_segment_id.id,
|
||||||
-source.GetReverseWeightPlusOffset(),
|
-phantom_node.GetReverseWeightPlusOffset(),
|
||||||
source.reverse_segment_id.id);
|
{phantom_node.reverse_segment_id.id,
|
||||||
}
|
-phantom_node.GetReverseDuration(),
|
||||||
|
-phantom_node.GetReverseDistance()});
|
||||||
const auto &target = nodes.target_phantom;
|
|
||||||
if (target.IsValidForwardTarget())
|
|
||||||
{
|
|
||||||
reverse_heap.Insert(target.forward_segment_id.id,
|
|
||||||
target.GetForwardWeightPlusOffset(),
|
|
||||||
target.forward_segment_id.id);
|
|
||||||
}
|
|
||||||
|
|
||||||
if (target.IsValidReverseTarget())
|
|
||||||
{
|
|
||||||
reverse_heap.Insert(target.reverse_segment_id.id,
|
|
||||||
target.GetReverseWeightPlusOffset(),
|
|
||||||
target.reverse_segment_id.id);
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
template <typename ManyToManyQueryHeap>
|
template <typename Algorithm>
|
||||||
void insertSourceInHeap(ManyToManyQueryHeap &heap, const PhantomNode &phantom_node)
|
void insertTargetInHeap(typename SearchEngineData<Algorithm>::ManyToManyQueryHeap &heap,
|
||||||
|
const PhantomNode &phantom_node)
|
||||||
|
{
|
||||||
|
if (phantom_node.IsValidForwardTarget())
|
||||||
|
{
|
||||||
|
heap.Insert(phantom_node.forward_segment_id.id,
|
||||||
|
phantom_node.GetForwardWeightPlusOffset(),
|
||||||
|
{phantom_node.forward_segment_id.id,
|
||||||
|
phantom_node.GetForwardDuration(),
|
||||||
|
phantom_node.GetForwardDistance()});
|
||||||
|
}
|
||||||
|
if (phantom_node.IsValidReverseTarget())
|
||||||
|
{
|
||||||
|
heap.Insert(phantom_node.reverse_segment_id.id,
|
||||||
|
phantom_node.GetReverseWeightPlusOffset(),
|
||||||
|
{phantom_node.reverse_segment_id.id,
|
||||||
|
phantom_node.GetReverseDuration(),
|
||||||
|
phantom_node.GetReverseDistance()});
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
template <typename Algorithm>
|
||||||
|
void insertSourceInHeap(typename SearchEngineData<Algorithm>::QueryHeap &heap,
|
||||||
|
const PhantomNode &phantom_node)
|
||||||
|
{
|
||||||
|
if (phantom_node.IsValidForwardSource())
|
||||||
|
{
|
||||||
|
heap.Insert(phantom_node.forward_segment_id.id,
|
||||||
|
-phantom_node.GetForwardWeightPlusOffset(),
|
||||||
|
phantom_node.forward_segment_id.id);
|
||||||
|
}
|
||||||
|
if (phantom_node.IsValidReverseSource())
|
||||||
|
{
|
||||||
|
heap.Insert(phantom_node.reverse_segment_id.id,
|
||||||
|
-phantom_node.GetReverseWeightPlusOffset(),
|
||||||
|
phantom_node.reverse_segment_id.id);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
template <typename Algorithm>
|
||||||
|
void insertTargetInHeap(typename SearchEngineData<Algorithm>::QueryHeap &heap,
|
||||||
|
const PhantomNode &phantom_node)
|
||||||
|
{
|
||||||
|
if (phantom_node.IsValidForwardTarget())
|
||||||
|
{
|
||||||
|
heap.Insert(phantom_node.forward_segment_id.id,
|
||||||
|
phantom_node.GetForwardWeightPlusOffset(),
|
||||||
|
phantom_node.forward_segment_id.id);
|
||||||
|
}
|
||||||
|
if (phantom_node.IsValidReverseTarget())
|
||||||
|
{
|
||||||
|
heap.Insert(phantom_node.reverse_segment_id.id,
|
||||||
|
phantom_node.GetReverseWeightPlusOffset(),
|
||||||
|
phantom_node.reverse_segment_id.id);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
} // namespace detail
|
||||||
|
|
||||||
|
inline void insertTargetInHeap(typename SearchEngineData<mld::Algorithm>::ManyToManyQueryHeap &heap,
|
||||||
|
const PhantomNode &phantom_node)
|
||||||
|
{
|
||||||
|
detail::insertTargetInHeap<mld::Algorithm>(heap, phantom_node);
|
||||||
|
}
|
||||||
|
inline void insertTargetInHeap(typename SearchEngineData<ch::Algorithm>::ManyToManyQueryHeap &heap,
|
||||||
|
const PhantomNode &phantom_node)
|
||||||
|
{
|
||||||
|
detail::insertTargetInHeap<ch::Algorithm>(heap, phantom_node);
|
||||||
|
}
|
||||||
|
inline void insertTargetInHeap(typename SearchEngineData<mld::Algorithm>::QueryHeap &heap,
|
||||||
|
const PhantomNode &phantom_node)
|
||||||
|
{
|
||||||
|
detail::insertTargetInHeap<mld::Algorithm>(heap, phantom_node);
|
||||||
|
}
|
||||||
|
inline void insertTargetInHeap(typename SearchEngineData<ch::Algorithm>::QueryHeap &heap,
|
||||||
|
const PhantomNode &phantom_node)
|
||||||
|
{
|
||||||
|
detail::insertTargetInHeap<ch::Algorithm>(heap, phantom_node);
|
||||||
|
}
|
||||||
|
inline void insertSourceInHeap(typename SearchEngineData<mld::Algorithm>::ManyToManyQueryHeap &heap,
|
||||||
|
const PhantomNode &phantom_node)
|
||||||
|
{
|
||||||
|
detail::insertSourceInHeap<mld::Algorithm>(heap, phantom_node);
|
||||||
|
}
|
||||||
|
inline void insertSourceInHeap(typename SearchEngineData<ch::Algorithm>::ManyToManyQueryHeap &heap,
|
||||||
|
const PhantomNode &phantom_node)
|
||||||
|
{
|
||||||
|
detail::insertSourceInHeap<ch::Algorithm>(heap, phantom_node);
|
||||||
|
}
|
||||||
|
inline void insertSourceInHeap(typename SearchEngineData<mld::Algorithm>::QueryHeap &heap,
|
||||||
|
const PhantomNode &phantom_node)
|
||||||
|
{
|
||||||
|
detail::insertSourceInHeap<mld::Algorithm>(heap, phantom_node);
|
||||||
|
}
|
||||||
|
inline void insertSourceInHeap(typename SearchEngineData<ch::Algorithm>::QueryHeap &heap,
|
||||||
|
const PhantomNode &phantom_node)
|
||||||
|
{
|
||||||
|
detail::insertSourceInHeap<ch::Algorithm>(heap, phantom_node);
|
||||||
|
}
|
||||||
|
|
||||||
|
template <typename Heap>
|
||||||
|
void insertNodesInHeaps(Heap &forward_heap, Heap &reverse_heap, const PhantomNodes &nodes)
|
||||||
|
{
|
||||||
|
insertSourceInHeap(forward_heap, nodes.source_phantom);
|
||||||
|
insertTargetInHeap(reverse_heap, nodes.target_phantom);
|
||||||
|
}
|
||||||
|
|
||||||
|
template <typename Algorithm>
|
||||||
|
void insertSourceInHeap(typename SearchEngineData<Algorithm>::ManyToManyQueryHeap &heap,
|
||||||
|
const PhantomNode &phantom_node)
|
||||||
{
|
{
|
||||||
if (phantom_node.IsValidForwardSource())
|
if (phantom_node.IsValidForwardSource())
|
||||||
{
|
{
|
||||||
@@ -95,23 +193,6 @@ void insertSourceInHeap(ManyToManyQueryHeap &heap, const PhantomNode &phantom_no
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
template <typename ManyToManyQueryHeap>
|
|
||||||
void insertTargetInHeap(ManyToManyQueryHeap &heap, const PhantomNode &phantom_node)
|
|
||||||
{
|
|
||||||
if (phantom_node.IsValidForwardTarget())
|
|
||||||
{
|
|
||||||
heap.Insert(phantom_node.forward_segment_id.id,
|
|
||||||
phantom_node.GetForwardWeightPlusOffset(),
|
|
||||||
{phantom_node.forward_segment_id.id, phantom_node.GetForwardDuration()});
|
|
||||||
}
|
|
||||||
if (phantom_node.IsValidReverseTarget())
|
|
||||||
{
|
|
||||||
heap.Insert(phantom_node.reverse_segment_id.id,
|
|
||||||
phantom_node.GetReverseWeightPlusOffset(),
|
|
||||||
{phantom_node.reverse_segment_id.id, phantom_node.GetReverseDuration()});
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
template <typename FacadeT>
|
template <typename FacadeT>
|
||||||
void annotatePath(const FacadeT &facade,
|
void annotatePath(const FacadeT &facade,
|
||||||
const PhantomNodes &phantom_node_pair,
|
const PhantomNodes &phantom_node_pair,
|
||||||
@@ -181,6 +262,7 @@ void annotatePath(const FacadeT &facade,
|
|||||||
BOOST_ASSERT(datasource_vector.size() > 0);
|
BOOST_ASSERT(datasource_vector.size() > 0);
|
||||||
BOOST_ASSERT(weight_vector.size() + 1 == id_vector.size());
|
BOOST_ASSERT(weight_vector.size() + 1 == id_vector.size());
|
||||||
BOOST_ASSERT(duration_vector.size() + 1 == id_vector.size());
|
BOOST_ASSERT(duration_vector.size() + 1 == id_vector.size());
|
||||||
|
|
||||||
const bool is_first_segment = unpacked_path.empty();
|
const bool is_first_segment = unpacked_path.empty();
|
||||||
|
|
||||||
const std::size_t start_index =
|
const std::size_t start_index =
|
||||||
@@ -320,58 +402,10 @@ void annotatePath(const FacadeT &facade,
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
template <typename Algorithm>
|
EdgeDistance adjustPathDistanceToPhantomNodes(const std::vector<NodeID> &path,
|
||||||
double getPathDistance(const DataFacade<Algorithm> &facade,
|
const PhantomNode &source_phantom,
|
||||||
const std::vector<PathData> unpacked_path,
|
const PhantomNode &target_phantom,
|
||||||
const PhantomNode &source_phantom,
|
const EdgeDistance distance);
|
||||||
const PhantomNode &target_phantom)
|
|
||||||
{
|
|
||||||
using util::coordinate_calculation::detail::DEGREE_TO_RAD;
|
|
||||||
using util::coordinate_calculation::detail::EARTH_RADIUS;
|
|
||||||
|
|
||||||
double distance = 0;
|
|
||||||
double prev_lat =
|
|
||||||
static_cast<double>(util::toFloating(source_phantom.location.lat)) * DEGREE_TO_RAD;
|
|
||||||
double prev_lon =
|
|
||||||
static_cast<double>(util::toFloating(source_phantom.location.lon)) * DEGREE_TO_RAD;
|
|
||||||
double prev_cos = std::cos(prev_lat);
|
|
||||||
for (const auto &p : unpacked_path)
|
|
||||||
{
|
|
||||||
const auto current_coordinate = facade.GetCoordinateOfNode(p.turn_via_node);
|
|
||||||
|
|
||||||
const double current_lat =
|
|
||||||
static_cast<double>(util::toFloating(current_coordinate.lat)) * DEGREE_TO_RAD;
|
|
||||||
const double current_lon =
|
|
||||||
static_cast<double>(util::toFloating(current_coordinate.lon)) * DEGREE_TO_RAD;
|
|
||||||
const double current_cos = std::cos(current_lat);
|
|
||||||
|
|
||||||
const double sin_dlon = std::sin((prev_lon - current_lon) / 2.0);
|
|
||||||
const double sin_dlat = std::sin((prev_lat - current_lat) / 2.0);
|
|
||||||
|
|
||||||
const double aharv = sin_dlat * sin_dlat + prev_cos * current_cos * sin_dlon * sin_dlon;
|
|
||||||
const double charv = 2. * std::atan2(std::sqrt(aharv), std::sqrt(1.0 - aharv));
|
|
||||||
distance += EARTH_RADIUS * charv;
|
|
||||||
|
|
||||||
prev_lat = current_lat;
|
|
||||||
prev_lon = current_lon;
|
|
||||||
prev_cos = current_cos;
|
|
||||||
}
|
|
||||||
|
|
||||||
const double current_lat =
|
|
||||||
static_cast<double>(util::toFloating(target_phantom.location.lat)) * DEGREE_TO_RAD;
|
|
||||||
const double current_lon =
|
|
||||||
static_cast<double>(util::toFloating(target_phantom.location.lon)) * DEGREE_TO_RAD;
|
|
||||||
const double current_cos = std::cos(current_lat);
|
|
||||||
|
|
||||||
const double sin_dlon = std::sin((prev_lon - current_lon) / 2.0);
|
|
||||||
const double sin_dlat = std::sin((prev_lat - current_lat) / 2.0);
|
|
||||||
|
|
||||||
const double aharv = sin_dlat * sin_dlat + prev_cos * current_cos * sin_dlon * sin_dlon;
|
|
||||||
const double charv = 2. * std::atan2(std::sqrt(aharv), std::sqrt(1.0 - aharv));
|
|
||||||
distance += EARTH_RADIUS * charv;
|
|
||||||
|
|
||||||
return distance;
|
|
||||||
}
|
|
||||||
|
|
||||||
template <typename AlgorithmT>
|
template <typename AlgorithmT>
|
||||||
InternalRouteResult extractRoute(const DataFacade<AlgorithmT> &facade,
|
InternalRouteResult extractRoute(const DataFacade<AlgorithmT> &facade,
|
||||||
@@ -405,6 +439,22 @@ InternalRouteResult extractRoute(const DataFacade<AlgorithmT> &facade,
|
|||||||
return raw_route_data;
|
return raw_route_data;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
template <typename FacadeT> EdgeDistance computeEdgeDistance(const FacadeT &facade, NodeID node_id)
|
||||||
|
{
|
||||||
|
const auto geometry_index = facade.GetGeometryIndex(node_id);
|
||||||
|
|
||||||
|
EdgeDistance total_distance = 0.0;
|
||||||
|
|
||||||
|
auto geometry_range = facade.GetUncompressedForwardGeometry(geometry_index.id);
|
||||||
|
for (auto current = geometry_range.begin(); current < geometry_range.end() - 1; ++current)
|
||||||
|
{
|
||||||
|
total_distance += util::coordinate_calculation::fccApproximateDistance(
|
||||||
|
facade.GetCoordinateOfNode(*current), facade.GetCoordinateOfNode(*std::next(current)));
|
||||||
|
}
|
||||||
|
|
||||||
|
return total_distance;
|
||||||
|
}
|
||||||
|
|
||||||
} // namespace routing_algorithms
|
} // namespace routing_algorithms
|
||||||
} // namespace engine
|
} // namespace engine
|
||||||
} // namespace osrm
|
} // namespace osrm
|
||||||
|
|||||||
@@ -186,9 +186,10 @@ void routingStep(const DataFacade<Algorithm> &facade,
|
|||||||
}
|
}
|
||||||
|
|
||||||
template <bool UseDuration>
|
template <bool UseDuration>
|
||||||
EdgeWeight getLoopWeight(const DataFacade<Algorithm> &facade, NodeID node)
|
std::tuple<EdgeWeight,EdgeDistance> getLoopWeight(const DataFacade<Algorithm> &facade, NodeID node)
|
||||||
{
|
{
|
||||||
EdgeWeight loop_weight = UseDuration ? MAXIMAL_EDGE_DURATION : INVALID_EDGE_WEIGHT;
|
EdgeWeight loop_weight = UseDuration ? MAXIMAL_EDGE_DURATION : INVALID_EDGE_WEIGHT;
|
||||||
|
EdgeDistance loop_distance = MAXIMAL_EDGE_DISTANCE;
|
||||||
for (auto edge : facade.GetAdjacentEdgeRange(node))
|
for (auto edge : facade.GetAdjacentEdgeRange(node))
|
||||||
{
|
{
|
||||||
const auto &data = facade.GetEdgeData(edge);
|
const auto &data = facade.GetEdgeData(edge);
|
||||||
@@ -198,11 +199,15 @@ EdgeWeight getLoopWeight(const DataFacade<Algorithm> &facade, NodeID node)
|
|||||||
if (to == node)
|
if (to == node)
|
||||||
{
|
{
|
||||||
const auto value = UseDuration ? data.duration : data.weight;
|
const auto value = UseDuration ? data.duration : data.weight;
|
||||||
loop_weight = std::min(loop_weight, value);
|
if (value < loop_weight)
|
||||||
|
{
|
||||||
|
loop_weight = value;
|
||||||
|
loop_distance = data.distance;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
return loop_weight;
|
return std::make_tuple(loop_weight, loop_distance);
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@@ -288,6 +293,106 @@ void unpackPath(const DataFacade<Algorithm> &facade,
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
template <typename BidirectionalIterator>
|
||||||
|
EdgeDistance calculateEBGNodeAnnotations(const DataFacade<Algorithm> &facade,
|
||||||
|
BidirectionalIterator packed_path_begin,
|
||||||
|
BidirectionalIterator packed_path_end)
|
||||||
|
{
|
||||||
|
// Make sure we have at least something to unpack
|
||||||
|
if (packed_path_begin == packed_path_end ||
|
||||||
|
std::distance(packed_path_begin, packed_path_end) <= 1)
|
||||||
|
return 0;
|
||||||
|
|
||||||
|
std::stack<std::tuple<NodeID, NodeID, bool>> recursion_stack;
|
||||||
|
std::stack<EdgeDistance> distance_stack;
|
||||||
|
// We have to push the path in reverse order onto the stack because it's LIFO.
|
||||||
|
for (auto current = std::prev(packed_path_end); current > packed_path_begin;
|
||||||
|
current = std::prev(current))
|
||||||
|
{
|
||||||
|
recursion_stack.emplace(*std::prev(current), *current, false);
|
||||||
|
}
|
||||||
|
|
||||||
|
std::tuple<NodeID, NodeID, bool> edge;
|
||||||
|
while (!recursion_stack.empty())
|
||||||
|
{
|
||||||
|
edge = recursion_stack.top();
|
||||||
|
recursion_stack.pop();
|
||||||
|
|
||||||
|
// Have we processed the edge before? tells us if we have values in the durations stack that
|
||||||
|
// we can add up
|
||||||
|
if (!std::get<2>(edge))
|
||||||
|
{ // haven't processed edge before, so process it in the body!
|
||||||
|
|
||||||
|
std::get<2>(edge) = true; // mark that this edge will now be processed
|
||||||
|
|
||||||
|
// Look for an edge on the forward CH graph (.forward)
|
||||||
|
EdgeID smaller_edge_id =
|
||||||
|
facade.FindSmallestEdge(std::get<0>(edge), std::get<1>(edge), [](const auto &data) {
|
||||||
|
return data.forward;
|
||||||
|
});
|
||||||
|
|
||||||
|
// If we didn't find one there, the we might be looking at a part of the path that
|
||||||
|
// was found using the backward search. Here, we flip the node order (.second,
|
||||||
|
// .first) and only consider edges with the `.backward` flag.
|
||||||
|
if (SPECIAL_EDGEID == smaller_edge_id)
|
||||||
|
{
|
||||||
|
smaller_edge_id =
|
||||||
|
facade.FindSmallestEdge(std::get<1>(edge),
|
||||||
|
std::get<0>(edge),
|
||||||
|
[](const auto &data) { return data.backward; });
|
||||||
|
}
|
||||||
|
|
||||||
|
// If we didn't find anything *still*, then something is broken and someone has
|
||||||
|
// called this function with bad values.
|
||||||
|
BOOST_ASSERT_MSG(smaller_edge_id != SPECIAL_EDGEID, "Invalid smaller edge ID");
|
||||||
|
|
||||||
|
const auto &data = facade.GetEdgeData(smaller_edge_id);
|
||||||
|
BOOST_ASSERT_MSG(data.weight != std::numeric_limits<EdgeWeight>::max(),
|
||||||
|
"edge weight invalid");
|
||||||
|
|
||||||
|
// If the edge is a shortcut, we need to add the two halfs to the stack.
|
||||||
|
if (data.shortcut)
|
||||||
|
{ // unpack
|
||||||
|
const NodeID middle_node_id = data.turn_id;
|
||||||
|
// Note the order here - we're adding these to a stack, so we
|
||||||
|
// want the first->middle to get visited before middle->second
|
||||||
|
recursion_stack.emplace(edge);
|
||||||
|
recursion_stack.emplace(middle_node_id, std::get<1>(edge), false);
|
||||||
|
recursion_stack.emplace(std::get<0>(edge), middle_node_id, false);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
// compute the duration here and put it onto the duration stack using method
|
||||||
|
// similar to annotatePath but smaller
|
||||||
|
EdgeDistance distance = computeEdgeDistance(facade, std::get<0>(edge));
|
||||||
|
distance_stack.emplace(distance);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{ // the edge has already been processed. this means that there are enough values in the
|
||||||
|
// distances stack
|
||||||
|
|
||||||
|
BOOST_ASSERT_MSG(distance_stack.size() >= 2,
|
||||||
|
"There are not enough (at least 2) values on the distance stack");
|
||||||
|
EdgeDistance distance1 = distance_stack.top();
|
||||||
|
distance_stack.pop();
|
||||||
|
EdgeDistance distance2 = distance_stack.top();
|
||||||
|
distance_stack.pop();
|
||||||
|
EdgeDistance distance = distance1 + distance2;
|
||||||
|
distance_stack.emplace(distance);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
EdgeDistance total_distance = 0;
|
||||||
|
while (!distance_stack.empty())
|
||||||
|
{
|
||||||
|
total_distance += distance_stack.top();
|
||||||
|
distance_stack.pop();
|
||||||
|
}
|
||||||
|
|
||||||
|
return total_distance;
|
||||||
|
}
|
||||||
|
|
||||||
template <typename RandomIter, typename FacadeT>
|
template <typename RandomIter, typename FacadeT>
|
||||||
void unpackPath(const FacadeT &facade,
|
void unpackPath(const FacadeT &facade,
|
||||||
RandomIter packed_path_begin,
|
RandomIter packed_path_begin,
|
||||||
@@ -340,6 +445,11 @@ void retrievePackedPathFromSingleHeap(const SearchEngineData<Algorithm>::QueryHe
|
|||||||
const NodeID middle_node_id,
|
const NodeID middle_node_id,
|
||||||
std::vector<NodeID> &packed_path);
|
std::vector<NodeID> &packed_path);
|
||||||
|
|
||||||
|
void retrievePackedPathFromSingleManyToManyHeap(
|
||||||
|
const SearchEngineData<Algorithm>::ManyToManyQueryHeap &search_heap,
|
||||||
|
const NodeID middle_node_id,
|
||||||
|
std::vector<NodeID> &packed_path);
|
||||||
|
|
||||||
// assumes that heaps are already setup correctly.
|
// assumes that heaps are already setup correctly.
|
||||||
// ATTENTION: This only works if no additional offset is supplied next to the Phantom Node
|
// ATTENTION: This only works if no additional offset is supplied next to the Phantom Node
|
||||||
// Offsets.
|
// Offsets.
|
||||||
|
|||||||
@@ -54,7 +54,7 @@ inline bool checkParentCellRestriction(CellID, const PhantomNodes &) { return tr
|
|||||||
|
|
||||||
// Restricted search (Args is LevelID, CellID):
|
// Restricted search (Args is LevelID, CellID):
|
||||||
// * use the fixed level for queries
|
// * use the fixed level for queries
|
||||||
// * check if the node cell is the same as the specified parent onr
|
// * check if the node cell is the same as the specified parent
|
||||||
template <typename MultiLevelPartition>
|
template <typename MultiLevelPartition>
|
||||||
inline LevelID getNodeQueryLevel(const MultiLevelPartition &, NodeID, LevelID level, CellID)
|
inline LevelID getNodeQueryLevel(const MultiLevelPartition &, NodeID, LevelID level, CellID)
|
||||||
{
|
{
|
||||||
@@ -65,8 +65,62 @@ inline bool checkParentCellRestriction(CellID cell, LevelID, CellID parent)
|
|||||||
{
|
{
|
||||||
return cell == parent;
|
return cell == parent;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Unrestricted search with a single phantom node (Args is const PhantomNode &):
|
||||||
|
// * use partition.GetQueryLevel to find the node query level
|
||||||
|
// * allow to traverse all cells
|
||||||
|
template <typename MultiLevelPartition>
|
||||||
|
inline LevelID getNodeQueryLevel(const MultiLevelPartition &partition,
|
||||||
|
const NodeID node,
|
||||||
|
const PhantomNode &phantom_node)
|
||||||
|
{
|
||||||
|
auto highest_diffrent_level = [&partition, node](const SegmentID &phantom_node) {
|
||||||
|
if (phantom_node.enabled)
|
||||||
|
return partition.GetHighestDifferentLevel(phantom_node.id, node);
|
||||||
|
return INVALID_LEVEL_ID;
|
||||||
|
};
|
||||||
|
|
||||||
|
const auto node_level = std::min(highest_diffrent_level(phantom_node.forward_segment_id),
|
||||||
|
highest_diffrent_level(phantom_node.reverse_segment_id));
|
||||||
|
|
||||||
|
return node_level;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Unrestricted search with a single phantom node and a vector of phantom nodes:
|
||||||
|
// * use partition.GetQueryLevel to find the node query level
|
||||||
|
// * allow to traverse all cells
|
||||||
|
template <typename MultiLevelPartition>
|
||||||
|
inline LevelID getNodeQueryLevel(const MultiLevelPartition &partition,
|
||||||
|
NodeID node,
|
||||||
|
const std::vector<PhantomNode> &phantom_nodes,
|
||||||
|
const std::size_t phantom_index,
|
||||||
|
const std::vector<std::size_t> &phantom_indices)
|
||||||
|
{
|
||||||
|
auto min_level = [&partition, node](const PhantomNode &phantom_node) {
|
||||||
|
const auto &forward_segment = phantom_node.forward_segment_id;
|
||||||
|
const auto forward_level =
|
||||||
|
forward_segment.enabled ? partition.GetHighestDifferentLevel(node, forward_segment.id)
|
||||||
|
: INVALID_LEVEL_ID;
|
||||||
|
|
||||||
|
const auto &reverse_segment = phantom_node.reverse_segment_id;
|
||||||
|
const auto reverse_level =
|
||||||
|
reverse_segment.enabled ? partition.GetHighestDifferentLevel(node, reverse_segment.id)
|
||||||
|
: INVALID_LEVEL_ID;
|
||||||
|
|
||||||
|
return std::min(forward_level, reverse_level);
|
||||||
|
};
|
||||||
|
|
||||||
|
// Get minimum level over all phantoms of the highest different level with respect to node
|
||||||
|
// This is equivalent to min_{∀ source, target} partition.GetQueryLevel(source, node, target)
|
||||||
|
auto result = min_level(phantom_nodes[phantom_index]);
|
||||||
|
for (const auto &index : phantom_indices)
|
||||||
|
{
|
||||||
|
result = std::min(result, min_level(phantom_nodes[index]));
|
||||||
|
}
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
} // namespace
|
||||||
|
|
||||||
// Heaps only record for each node its predecessor ("parent") on the shortest path.
|
// Heaps only record for each node its predecessor ("parent") on the shortest path.
|
||||||
// For re-constructing the actual path we need to trace back all parent "pointers".
|
// For re-constructing the actual path we need to trace back all parent "pointers".
|
||||||
// In contrast to the CH code MLD needs to know the edges (with clique arc property).
|
// In contrast to the CH code MLD needs to know the edges (with clique arc property).
|
||||||
@@ -74,6 +128,46 @@ inline bool checkParentCellRestriction(CellID cell, LevelID, CellID parent)
|
|||||||
using PackedEdge = std::tuple</*from*/ NodeID, /*to*/ NodeID, /*from_clique_arc*/ bool>;
|
using PackedEdge = std::tuple</*from*/ NodeID, /*to*/ NodeID, /*from_clique_arc*/ bool>;
|
||||||
using PackedPath = std::vector<PackedEdge>;
|
using PackedPath = std::vector<PackedEdge>;
|
||||||
|
|
||||||
|
template <bool DIRECTION, typename OutIter>
|
||||||
|
inline void retrievePackedPathFromSingleManyToManyHeap(
|
||||||
|
const SearchEngineData<Algorithm>::ManyToManyQueryHeap &heap, const NodeID middle, OutIter out)
|
||||||
|
{
|
||||||
|
|
||||||
|
NodeID current = middle;
|
||||||
|
NodeID parent = heap.GetData(current).parent;
|
||||||
|
|
||||||
|
while (current != parent)
|
||||||
|
{
|
||||||
|
const auto &data = heap.GetData(current);
|
||||||
|
|
||||||
|
if (DIRECTION == FORWARD_DIRECTION)
|
||||||
|
{
|
||||||
|
*out = std::make_tuple(parent, current, data.from_clique_arc);
|
||||||
|
++out;
|
||||||
|
}
|
||||||
|
else if (DIRECTION == REVERSE_DIRECTION)
|
||||||
|
{
|
||||||
|
*out = std::make_tuple(current, parent, data.from_clique_arc);
|
||||||
|
++out;
|
||||||
|
}
|
||||||
|
|
||||||
|
current = parent;
|
||||||
|
parent = heap.GetData(parent).parent;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
template <bool DIRECTION>
|
||||||
|
inline PackedPath retrievePackedPathFromSingleManyToManyHeap(
|
||||||
|
const SearchEngineData<Algorithm>::ManyToManyQueryHeap &heap, const NodeID middle)
|
||||||
|
{
|
||||||
|
|
||||||
|
PackedPath packed_path;
|
||||||
|
retrievePackedPathFromSingleManyToManyHeap<DIRECTION>(
|
||||||
|
heap, middle, std::back_inserter(packed_path));
|
||||||
|
|
||||||
|
return packed_path;
|
||||||
|
}
|
||||||
|
|
||||||
template <bool DIRECTION, typename OutIter>
|
template <bool DIRECTION, typename OutIter>
|
||||||
inline void retrievePackedPathFromSingleHeap(const SearchEngineData<Algorithm>::QueryHeap &heap,
|
inline void retrievePackedPathFromSingleHeap(const SearchEngineData<Algorithm>::QueryHeap &heap,
|
||||||
const NodeID middle,
|
const NodeID middle,
|
||||||
@@ -206,15 +300,22 @@ void relaxOutgoingEdges(const DataFacade<Algorithm> &facade,
|
|||||||
for (const auto edge : facade.GetBorderEdgeRange(level, node))
|
for (const auto edge : facade.GetBorderEdgeRange(level, node))
|
||||||
{
|
{
|
||||||
const auto &edge_data = facade.GetEdgeData(edge);
|
const auto &edge_data = facade.GetEdgeData(edge);
|
||||||
if (DIRECTION == FORWARD_DIRECTION ? edge_data.forward : edge_data.backward)
|
|
||||||
|
if ((DIRECTION == FORWARD_DIRECTION) ? facade.IsForwardEdge(edge)
|
||||||
|
: facade.IsBackwardEdge(edge))
|
||||||
{
|
{
|
||||||
const NodeID to = facade.GetTarget(edge);
|
const NodeID to = facade.GetTarget(edge);
|
||||||
|
|
||||||
if (!facade.ExcludeNode(to) &&
|
if (!facade.ExcludeNode(to) &&
|
||||||
checkParentCellRestriction(partition.GetCell(level + 1, to), args...))
|
checkParentCellRestriction(partition.GetCell(level + 1, to), args...))
|
||||||
{
|
{
|
||||||
BOOST_ASSERT_MSG(edge_data.weight > 0, "edge_weight invalid");
|
const auto node_weight =
|
||||||
const EdgeWeight to_weight = weight + edge_data.weight;
|
facade.GetNodeWeight(DIRECTION == FORWARD_DIRECTION ? node : to);
|
||||||
|
const auto turn_penalty = facade.GetWeightPenaltyForEdgeID(edge_data.turn_id);
|
||||||
|
|
||||||
|
// TODO: BOOST_ASSERT(edge_data.weight == node_weight + turn_penalty);
|
||||||
|
|
||||||
|
const EdgeWeight to_weight = weight + node_weight + turn_penalty;
|
||||||
|
|
||||||
if (!forward_heap.WasInserted(to))
|
if (!forward_heap.WasInserted(to))
|
||||||
{
|
{
|
||||||
@@ -289,21 +390,27 @@ UnpackedPath search(SearchEngineData<Algorithm> &engine_working_data,
|
|||||||
EdgeWeight weight_upper_bound,
|
EdgeWeight weight_upper_bound,
|
||||||
Args... args)
|
Args... args)
|
||||||
{
|
{
|
||||||
if (forward_heap.Empty() || reverse_heap.Empty())
|
if (forward_heap.Empty() && reverse_heap.Empty())
|
||||||
{
|
{
|
||||||
return std::make_tuple(INVALID_EDGE_WEIGHT, std::vector<NodeID>(), std::vector<EdgeID>());
|
return std::make_tuple(INVALID_EDGE_WEIGHT, std::vector<NodeID>(), std::vector<EdgeID>());
|
||||||
}
|
}
|
||||||
|
|
||||||
const auto &partition = facade.GetMultiLevelPartition();
|
const auto &partition = facade.GetMultiLevelPartition();
|
||||||
|
|
||||||
BOOST_ASSERT(!forward_heap.Empty() && forward_heap.MinKey() < INVALID_EDGE_WEIGHT);
|
BOOST_ASSERT(forward_heap.Empty() || forward_heap.MinKey() < INVALID_EDGE_WEIGHT);
|
||||||
BOOST_ASSERT(!reverse_heap.Empty() && reverse_heap.MinKey() < INVALID_EDGE_WEIGHT);
|
BOOST_ASSERT(reverse_heap.Empty() || reverse_heap.MinKey() < INVALID_EDGE_WEIGHT);
|
||||||
|
|
||||||
// run two-Target Dijkstra routing step.
|
// run two-Target Dijkstra routing step.
|
||||||
NodeID middle = SPECIAL_NODEID;
|
NodeID middle = SPECIAL_NODEID;
|
||||||
EdgeWeight weight = weight_upper_bound;
|
EdgeWeight weight = weight_upper_bound;
|
||||||
EdgeWeight forward_heap_min = forward_heap.MinKey();
|
|
||||||
EdgeWeight reverse_heap_min = reverse_heap.MinKey();
|
EdgeWeight forward_heap_min = 0;
|
||||||
|
if (!forward_heap.Empty())
|
||||||
|
forward_heap_min = forward_heap.MinKey();
|
||||||
|
EdgeWeight reverse_heap_min = 0;
|
||||||
|
if (!reverse_heap.Empty())
|
||||||
|
reverse_heap_min = reverse_heap.MinKey();
|
||||||
|
|
||||||
while (forward_heap.Size() + reverse_heap.Size() > 0 &&
|
while (forward_heap.Size() + reverse_heap.Size() > 0 &&
|
||||||
forward_heap_min + reverse_heap_min < weight)
|
forward_heap_min + reverse_heap_min < weight)
|
||||||
{
|
{
|
||||||
@@ -407,6 +514,90 @@ UnpackedPath search(SearchEngineData<Algorithm> &engine_working_data,
|
|||||||
return std::make_tuple(weight, std::move(unpacked_nodes), std::move(unpacked_edges));
|
return std::make_tuple(weight, std::move(unpacked_nodes), std::move(unpacked_edges));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// With (s, middle, t) we trace back the paths middle -> s and middle -> t.
|
||||||
|
// This gives us a packed path (node ids) from the base graph around s and t,
|
||||||
|
// and overlay node ids otherwise. We then have to unpack the overlay clique
|
||||||
|
// edges by recursively descending unpacking the path down to the base graph.
|
||||||
|
|
||||||
|
using UnpackedNodes = std::vector<NodeID>;
|
||||||
|
using UnpackedEdges = std::vector<EdgeID>;
|
||||||
|
using UnpackedPath = std::tuple<EdgeWeight, UnpackedNodes, UnpackedEdges>;
|
||||||
|
|
||||||
|
template <typename Algorithm, typename... Args>
|
||||||
|
UnpackedPath
|
||||||
|
unpackPathAndCalculateDistance(SearchEngineData<Algorithm> &engine_working_data,
|
||||||
|
const DataFacade<Algorithm> &facade,
|
||||||
|
typename SearchEngineData<Algorithm>::QueryHeap &forward_heap,
|
||||||
|
typename SearchEngineData<Algorithm>::QueryHeap &reverse_heap,
|
||||||
|
const bool force_loop_forward,
|
||||||
|
const bool force_loop_reverse,
|
||||||
|
EdgeWeight weight_upper_bound,
|
||||||
|
PackedPath packed_path,
|
||||||
|
NodeID middle,
|
||||||
|
Args... args)
|
||||||
|
{
|
||||||
|
EdgeWeight weight = weight_upper_bound;
|
||||||
|
const auto &partition = facade.GetMultiLevelPartition();
|
||||||
|
const NodeID source_node = !packed_path.empty() ? std::get<0>(packed_path.front()) : middle;
|
||||||
|
|
||||||
|
// Unpack path
|
||||||
|
std::vector<NodeID> unpacked_nodes;
|
||||||
|
std::vector<EdgeID> unpacked_edges;
|
||||||
|
unpacked_nodes.reserve(packed_path.size());
|
||||||
|
unpacked_edges.reserve(packed_path.size());
|
||||||
|
|
||||||
|
unpacked_nodes.push_back(source_node);
|
||||||
|
|
||||||
|
for (auto const &packed_edge : packed_path)
|
||||||
|
{
|
||||||
|
NodeID source, target;
|
||||||
|
bool overlay_edge;
|
||||||
|
std::tie(source, target, overlay_edge) = packed_edge;
|
||||||
|
if (!overlay_edge)
|
||||||
|
{ // a base graph edge
|
||||||
|
unpacked_nodes.push_back(target);
|
||||||
|
unpacked_edges.push_back(facade.FindEdge(source, target));
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{ // an overlay graph edge
|
||||||
|
LevelID level = getNodeQueryLevel(partition, source, args...);
|
||||||
|
CellID parent_cell_id = partition.GetCell(level, source);
|
||||||
|
BOOST_ASSERT(parent_cell_id == partition.GetCell(level, target));
|
||||||
|
|
||||||
|
LevelID sublevel = level - 1;
|
||||||
|
|
||||||
|
// Here heaps can be reused, let's go deeper!
|
||||||
|
forward_heap.Clear();
|
||||||
|
reverse_heap.Clear();
|
||||||
|
forward_heap.Insert(source, 0, {source});
|
||||||
|
reverse_heap.Insert(target, 0, {target});
|
||||||
|
|
||||||
|
// TODO: when structured bindings will be allowed change to
|
||||||
|
// auto [subpath_weight, subpath_source, subpath_target, subpath] = ...
|
||||||
|
EdgeWeight subpath_weight;
|
||||||
|
std::vector<NodeID> subpath_nodes;
|
||||||
|
std::vector<EdgeID> subpath_edges;
|
||||||
|
std::tie(subpath_weight, subpath_nodes, subpath_edges) = search(engine_working_data,
|
||||||
|
facade,
|
||||||
|
forward_heap,
|
||||||
|
reverse_heap,
|
||||||
|
force_loop_forward,
|
||||||
|
force_loop_reverse,
|
||||||
|
weight_upper_bound,
|
||||||
|
sublevel,
|
||||||
|
parent_cell_id);
|
||||||
|
BOOST_ASSERT(!subpath_edges.empty());
|
||||||
|
BOOST_ASSERT(subpath_nodes.size() > 1);
|
||||||
|
BOOST_ASSERT(subpath_nodes.front() == source);
|
||||||
|
BOOST_ASSERT(subpath_nodes.back() == target);
|
||||||
|
unpacked_nodes.insert(
|
||||||
|
unpacked_nodes.end(), std::next(subpath_nodes.begin()), subpath_nodes.end());
|
||||||
|
unpacked_edges.insert(unpacked_edges.end(), subpath_edges.begin(), subpath_edges.end());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return std::make_tuple(weight, std::move(unpacked_nodes), std::move(unpacked_edges));
|
||||||
|
}
|
||||||
|
|
||||||
// Alias to be compatible with the CH-based search
|
// Alias to be compatible with the CH-based search
|
||||||
template <typename Algorithm>
|
template <typename Algorithm>
|
||||||
inline void search(SearchEngineData<Algorithm> &engine_working_data,
|
inline void search(SearchEngineData<Algorithm> &engine_working_data,
|
||||||
@@ -471,11 +662,7 @@ double getNetworkDistance(SearchEngineData<Algorithm> &engine_working_data,
|
|||||||
const PhantomNode &target_phantom,
|
const PhantomNode &target_phantom,
|
||||||
EdgeWeight weight_upper_bound = INVALID_EDGE_WEIGHT)
|
EdgeWeight weight_upper_bound = INVALID_EDGE_WEIGHT)
|
||||||
{
|
{
|
||||||
forward_heap.Clear();
|
|
||||||
reverse_heap.Clear();
|
|
||||||
|
|
||||||
const PhantomNodes phantom_nodes{source_phantom, target_phantom};
|
const PhantomNodes phantom_nodes{source_phantom, target_phantom};
|
||||||
insertNodesInHeaps(forward_heap, reverse_heap, phantom_nodes);
|
|
||||||
|
|
||||||
EdgeWeight weight = INVALID_EDGE_WEIGHT;
|
EdgeWeight weight = INVALID_EDGE_WEIGHT;
|
||||||
std::vector<NodeID> unpacked_nodes;
|
std::vector<NodeID> unpacked_nodes;
|
||||||
@@ -494,11 +681,22 @@ double getNetworkDistance(SearchEngineData<Algorithm> &engine_working_data,
|
|||||||
return std::numeric_limits<double>::max();
|
return std::numeric_limits<double>::max();
|
||||||
}
|
}
|
||||||
|
|
||||||
std::vector<PathData> unpacked_path;
|
EdgeDistance distance = 0;
|
||||||
|
|
||||||
annotatePath(facade, phantom_nodes, unpacked_nodes, unpacked_edges, unpacked_path);
|
if (!unpacked_nodes.empty())
|
||||||
|
{
|
||||||
|
distance = std::accumulate(unpacked_nodes.begin(),
|
||||||
|
std::prev(unpacked_nodes.end()),
|
||||||
|
EdgeDistance{0},
|
||||||
|
[&](const EdgeDistance distance, const auto node_id) {
|
||||||
|
return distance + computeEdgeDistance(facade, node_id);
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
return getPathDistance(facade, unpacked_path, source_phantom, target_phantom);
|
distance = adjustPathDistanceToPhantomNodes(
|
||||||
|
unpacked_nodes, phantom_nodes.source_phantom, phantom_nodes.target_phantom, distance);
|
||||||
|
|
||||||
|
return distance;
|
||||||
}
|
}
|
||||||
|
|
||||||
} // namespace mld
|
} // namespace mld
|
||||||
|
|||||||
@@ -30,7 +30,11 @@ struct HeapData
|
|||||||
struct ManyToManyHeapData : HeapData
|
struct ManyToManyHeapData : HeapData
|
||||||
{
|
{
|
||||||
EdgeWeight duration;
|
EdgeWeight duration;
|
||||||
ManyToManyHeapData(NodeID p, EdgeWeight duration) : HeapData(p), duration(duration) {}
|
EdgeDistance distance;
|
||||||
|
ManyToManyHeapData(NodeID p, EdgeWeight duration, EdgeDistance distance)
|
||||||
|
: HeapData(p), duration(duration), distance(distance)
|
||||||
|
{
|
||||||
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
template <> struct SearchEngineData<routing_algorithms::ch::Algorithm>
|
template <> struct SearchEngineData<routing_algorithms::ch::Algorithm>
|
||||||
@@ -75,12 +79,16 @@ struct MultiLayerDijkstraHeapData
|
|||||||
struct ManyToManyMultiLayerDijkstraHeapData : MultiLayerDijkstraHeapData
|
struct ManyToManyMultiLayerDijkstraHeapData : MultiLayerDijkstraHeapData
|
||||||
{
|
{
|
||||||
EdgeWeight duration;
|
EdgeWeight duration;
|
||||||
ManyToManyMultiLayerDijkstraHeapData(NodeID p, EdgeWeight duration)
|
EdgeDistance distance;
|
||||||
: MultiLayerDijkstraHeapData(p), duration(duration)
|
ManyToManyMultiLayerDijkstraHeapData(NodeID p, EdgeWeight duration, EdgeDistance distance)
|
||||||
|
: MultiLayerDijkstraHeapData(p), duration(duration), distance(distance)
|
||||||
{
|
{
|
||||||
}
|
}
|
||||||
ManyToManyMultiLayerDijkstraHeapData(NodeID p, bool from, EdgeWeight duration)
|
ManyToManyMultiLayerDijkstraHeapData(NodeID p,
|
||||||
: MultiLayerDijkstraHeapData(p, from), duration(duration)
|
bool from,
|
||||||
|
EdgeWeight duration,
|
||||||
|
EdgeDistance distance)
|
||||||
|
: MultiLayerDijkstraHeapData(p, from), duration(duration), distance(distance)
|
||||||
{
|
{
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
@@ -112,7 +120,7 @@ template <> struct SearchEngineData<routing_algorithms::mld::Algorithm>
|
|||||||
void InitializeOrClearManyToManyThreadLocalStorage(unsigned number_of_nodes,
|
void InitializeOrClearManyToManyThreadLocalStorage(unsigned number_of_nodes,
|
||||||
unsigned number_of_boundary_nodes);
|
unsigned number_of_boundary_nodes);
|
||||||
};
|
};
|
||||||
}
|
} // namespace engine
|
||||||
}
|
} // namespace osrm
|
||||||
|
|
||||||
#endif // SEARCH_ENGINE_DATA_HPP
|
#endif // SEARCH_ENGINE_DATA_HPP
|
||||||
|
|||||||
@@ -82,7 +82,7 @@ class CompressedEdgeContainer
|
|||||||
std::unordered_map<EdgeID, unsigned> m_reverse_edge_id_to_zipped_index_map;
|
std::unordered_map<EdgeID, unsigned> m_reverse_edge_id_to_zipped_index_map;
|
||||||
std::unique_ptr<SegmentDataContainer> segment_data;
|
std::unique_ptr<SegmentDataContainer> segment_data;
|
||||||
};
|
};
|
||||||
}
|
} // namespace extractor
|
||||||
}
|
} // namespace osrm
|
||||||
|
|
||||||
#endif // GEOMETRY_COMPRESSOR_HPP_
|
#endif // GEOMETRY_COMPRESSOR_HPP_
|
||||||
|
|||||||
@@ -15,20 +15,25 @@ struct EdgeBasedEdge
|
|||||||
public:
|
public:
|
||||||
struct EdgeData
|
struct EdgeData
|
||||||
{
|
{
|
||||||
EdgeData() : turn_id(0), weight(0), duration(0), forward(false), backward(false) {}
|
EdgeData()
|
||||||
|
: turn_id(0), weight(0), distance(0), duration(0), forward(false), backward(false)
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
EdgeData(const NodeID turn_id,
|
EdgeData(const NodeID turn_id,
|
||||||
const EdgeWeight weight,
|
const EdgeWeight weight,
|
||||||
|
const EdgeDistance distance,
|
||||||
const EdgeWeight duration,
|
const EdgeWeight duration,
|
||||||
const bool forward,
|
const bool forward,
|
||||||
const bool backward)
|
const bool backward)
|
||||||
: turn_id(turn_id), weight(weight), duration(duration), forward(forward),
|
: turn_id(turn_id), weight(weight), distance(distance), duration(duration),
|
||||||
backward(backward)
|
forward(forward), backward(backward)
|
||||||
{
|
{
|
||||||
}
|
}
|
||||||
|
|
||||||
NodeID turn_id; // ID of the edge based node (node based edge)
|
NodeID turn_id; // ID of the edge based node (node based edge)
|
||||||
EdgeWeight weight;
|
EdgeWeight weight;
|
||||||
|
EdgeDistance distance;
|
||||||
EdgeWeight duration : 30;
|
EdgeWeight duration : 30;
|
||||||
std::uint32_t forward : 1;
|
std::uint32_t forward : 1;
|
||||||
std::uint32_t backward : 1;
|
std::uint32_t backward : 1;
|
||||||
@@ -43,6 +48,7 @@ struct EdgeBasedEdge
|
|||||||
const NodeID edge_id,
|
const NodeID edge_id,
|
||||||
const EdgeWeight weight,
|
const EdgeWeight weight,
|
||||||
const EdgeWeight duration,
|
const EdgeWeight duration,
|
||||||
|
const EdgeDistance distance,
|
||||||
const bool forward,
|
const bool forward,
|
||||||
const bool backward);
|
const bool backward);
|
||||||
EdgeBasedEdge(const NodeID source, const NodeID target, const EdgeBasedEdge::EdgeData &data);
|
EdgeBasedEdge(const NodeID source, const NodeID target, const EdgeBasedEdge::EdgeData &data);
|
||||||
@@ -53,7 +59,7 @@ struct EdgeBasedEdge
|
|||||||
NodeID target;
|
NodeID target;
|
||||||
EdgeData data;
|
EdgeData data;
|
||||||
};
|
};
|
||||||
static_assert(sizeof(extractor::EdgeBasedEdge) == 20,
|
static_assert(sizeof(extractor::EdgeBasedEdge) == 24,
|
||||||
"Size of extractor::EdgeBasedEdge type is "
|
"Size of extractor::EdgeBasedEdge type is "
|
||||||
"bigger than expected. This will influence "
|
"bigger than expected. This will influence "
|
||||||
"memory consumption.");
|
"memory consumption.");
|
||||||
@@ -67,9 +73,10 @@ inline EdgeBasedEdge::EdgeBasedEdge(const NodeID source,
|
|||||||
const NodeID turn_id,
|
const NodeID turn_id,
|
||||||
const EdgeWeight weight,
|
const EdgeWeight weight,
|
||||||
const EdgeWeight duration,
|
const EdgeWeight duration,
|
||||||
|
const EdgeDistance distance,
|
||||||
const bool forward,
|
const bool forward,
|
||||||
const bool backward)
|
const bool backward)
|
||||||
: source(source), target(target), data{turn_id, weight, duration, forward, backward}
|
: source(source), target(target), data{turn_id, weight, distance, duration, forward, backward}
|
||||||
{
|
{
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -89,7 +96,7 @@ inline bool EdgeBasedEdge::operator<(const EdgeBasedEdge &other) const
|
|||||||
return std::tie(source, target, data.weight, unidirectional) <
|
return std::tie(source, target, data.weight, unidirectional) <
|
||||||
std::tie(other.source, other.target, other.data.weight, other_is_unidirectional);
|
std::tie(other.source, other.target, other.data.weight, other_is_unidirectional);
|
||||||
}
|
}
|
||||||
} // ns extractor
|
} // namespace extractor
|
||||||
} // ns osrm
|
} // namespace osrm
|
||||||
|
|
||||||
#endif /* EDGE_BASED_EDGE_HPP */
|
#endif /* EDGE_BASED_EDGE_HPP */
|
||||||
|
|||||||
@@ -91,6 +91,7 @@ class EdgeBasedGraphFactory
|
|||||||
void GetEdgeBasedNodeSegments(std::vector<EdgeBasedNodeSegment> &nodes);
|
void GetEdgeBasedNodeSegments(std::vector<EdgeBasedNodeSegment> &nodes);
|
||||||
void GetStartPointMarkers(std::vector<bool> &node_is_startpoint);
|
void GetStartPointMarkers(std::vector<bool> &node_is_startpoint);
|
||||||
void GetEdgeBasedNodeWeights(std::vector<EdgeWeight> &output_node_weights);
|
void GetEdgeBasedNodeWeights(std::vector<EdgeWeight> &output_node_weights);
|
||||||
|
void GetEdgeBasedNodeDurations(std::vector<EdgeWeight> &output_node_durations);
|
||||||
std::uint32_t GetConnectivityChecksum() const;
|
std::uint32_t GetConnectivityChecksum() const;
|
||||||
|
|
||||||
std::uint64_t GetNumberOfEdgeBasedNodes() const;
|
std::uint64_t GetNumberOfEdgeBasedNodes() const;
|
||||||
@@ -117,6 +118,7 @@ class EdgeBasedGraphFactory
|
|||||||
//! node weights that indicate the length of the segment (node based) represented by the
|
//! node weights that indicate the length of the segment (node based) represented by the
|
||||||
//! edge-based node
|
//! edge-based node
|
||||||
std::vector<EdgeWeight> m_edge_based_node_weights;
|
std::vector<EdgeWeight> m_edge_based_node_weights;
|
||||||
|
std::vector<EdgeDuration> m_edge_based_node_durations;
|
||||||
|
|
||||||
//! list of edge based nodes (compressed segments)
|
//! list of edge based nodes (compressed segments)
|
||||||
std::vector<EdgeBasedNodeSegment> m_edge_based_node_segments;
|
std::vector<EdgeBasedNodeSegment> m_edge_based_node_segments;
|
||||||
|
|||||||
@@ -87,6 +87,7 @@ class Extractor
|
|||||||
std::vector<EdgeBasedNodeSegment> &edge_based_node_segments,
|
std::vector<EdgeBasedNodeSegment> &edge_based_node_segments,
|
||||||
std::vector<bool> &node_is_startpoint,
|
std::vector<bool> &node_is_startpoint,
|
||||||
std::vector<EdgeWeight> &edge_based_node_weights,
|
std::vector<EdgeWeight> &edge_based_node_weights,
|
||||||
|
std::vector<EdgeDuration> &edge_based_node_durations,
|
||||||
util::DeallocatingVector<EdgeBasedEdge> &edge_based_edge_list,
|
util::DeallocatingVector<EdgeBasedEdge> &edge_based_edge_list,
|
||||||
std::uint32_t &connectivity_checksum);
|
std::uint32_t &connectivity_checksum);
|
||||||
|
|
||||||
|
|||||||
@@ -462,14 +462,28 @@ void readEdgeBasedNodeWeights(const boost::filesystem::path &path, NodeWeigtsVec
|
|||||||
storage::serialization::read(reader, "/extractor/edge_based_node_weights", weights);
|
storage::serialization::read(reader, "/extractor/edge_based_node_weights", weights);
|
||||||
}
|
}
|
||||||
|
|
||||||
template <typename NodeWeigtsVectorT>
|
template <typename NodeWeigtsVectorT, typename NodeDurationsVectorT>
|
||||||
void writeEdgeBasedNodeWeights(const boost::filesystem::path &path,
|
void readEdgeBasedNodeWeightsDurations(const boost::filesystem::path &path,
|
||||||
const NodeWeigtsVectorT &weights)
|
NodeWeigtsVectorT &weights,
|
||||||
|
NodeDurationsVectorT &durations)
|
||||||
|
{
|
||||||
|
const auto fingerprint = storage::tar::FileReader::VerifyFingerprint;
|
||||||
|
storage::tar::FileReader reader{path, fingerprint};
|
||||||
|
|
||||||
|
storage::serialization::read(reader, "/extractor/edge_based_node_weights", weights);
|
||||||
|
storage::serialization::read(reader, "/extractor/edge_based_node_durations", durations);
|
||||||
|
}
|
||||||
|
|
||||||
|
template <typename NodeWeigtsVectorT, typename NodeDurationsVectorT>
|
||||||
|
void writeEdgeBasedNodeWeightsDurations(const boost::filesystem::path &path,
|
||||||
|
const NodeWeigtsVectorT &weights,
|
||||||
|
const NodeDurationsVectorT &durations)
|
||||||
{
|
{
|
||||||
const auto fingerprint = storage::tar::FileWriter::GenerateFingerprint;
|
const auto fingerprint = storage::tar::FileWriter::GenerateFingerprint;
|
||||||
storage::tar::FileWriter writer{path, fingerprint};
|
storage::tar::FileWriter writer{path, fingerprint};
|
||||||
|
|
||||||
storage::serialization::write(writer, "/extractor/edge_based_node_weights", weights);
|
storage::serialization::write(writer, "/extractor/edge_based_node_weights", weights);
|
||||||
|
storage::serialization::write(writer, "/extractor/edge_based_node_durations", durations);
|
||||||
}
|
}
|
||||||
|
|
||||||
template <typename RTreeT>
|
template <typename RTreeT>
|
||||||
|
|||||||
@@ -49,7 +49,7 @@ struct ByEdgeOrByMeterValue
|
|||||||
using value_type = float;
|
using value_type = float;
|
||||||
value_type value;
|
value_type value;
|
||||||
};
|
};
|
||||||
}
|
} // namespace detail
|
||||||
|
|
||||||
struct InternalExtractorEdge
|
struct InternalExtractorEdge
|
||||||
{
|
{
|
||||||
@@ -63,7 +63,7 @@ struct InternalExtractorEdge
|
|||||||
WeightData weight_data,
|
WeightData weight_data,
|
||||||
DurationData duration_data,
|
DurationData duration_data,
|
||||||
util::Coordinate source_coordinate)
|
util::Coordinate source_coordinate)
|
||||||
: result(source, target, 0, 0, {}, -1, {}), weight_data(std::move(weight_data)),
|
: result(source, target, 0, 0, 0, {}, -1, {}), weight_data(std::move(weight_data)),
|
||||||
duration_data(std::move(duration_data)), source_coordinate(std::move(source_coordinate))
|
duration_data(std::move(duration_data)), source_coordinate(std::move(source_coordinate))
|
||||||
{
|
{
|
||||||
}
|
}
|
||||||
@@ -113,7 +113,7 @@ struct InternalExtractorEdge
|
|||||||
return v;
|
return v;
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
}
|
} // namespace extractor
|
||||||
}
|
} // namespace osrm
|
||||||
|
|
||||||
#endif // INTERNAL_EXTRACTOR_EDGE_HPP
|
#endif // INTERNAL_EXTRACTOR_EDGE_HPP
|
||||||
|
|||||||
@@ -97,6 +97,7 @@ struct NodeBasedEdge
|
|||||||
NodeID target,
|
NodeID target,
|
||||||
EdgeWeight weight,
|
EdgeWeight weight,
|
||||||
EdgeDuration duration,
|
EdgeDuration duration,
|
||||||
|
EdgeDistance distance,
|
||||||
GeometryID geometry_id,
|
GeometryID geometry_id,
|
||||||
AnnotationID annotation_data,
|
AnnotationID annotation_data,
|
||||||
NodeBasedEdgeClassification flags);
|
NodeBasedEdgeClassification flags);
|
||||||
@@ -107,6 +108,7 @@ struct NodeBasedEdge
|
|||||||
NodeID target; // 32 4
|
NodeID target; // 32 4
|
||||||
EdgeWeight weight; // 32 4
|
EdgeWeight weight; // 32 4
|
||||||
EdgeDuration duration; // 32 4
|
EdgeDuration duration; // 32 4
|
||||||
|
EdgeDistance distance; // 32 4
|
||||||
GeometryID geometry_id; // 32 4
|
GeometryID geometry_id; // 32 4
|
||||||
AnnotationID annotation_data; // 32 4
|
AnnotationID annotation_data; // 32 4
|
||||||
NodeBasedEdgeClassification flags; // 32 4
|
NodeBasedEdgeClassification flags; // 32 4
|
||||||
@@ -120,6 +122,7 @@ struct NodeBasedEdgeWithOSM : NodeBasedEdge
|
|||||||
OSMNodeID target,
|
OSMNodeID target,
|
||||||
EdgeWeight weight,
|
EdgeWeight weight,
|
||||||
EdgeDuration duration,
|
EdgeDuration duration,
|
||||||
|
EdgeDistance distance,
|
||||||
GeometryID geometry_id,
|
GeometryID geometry_id,
|
||||||
AnnotationID annotation_data,
|
AnnotationID annotation_data,
|
||||||
NodeBasedEdgeClassification flags);
|
NodeBasedEdgeClassification flags);
|
||||||
@@ -137,7 +140,8 @@ inline NodeBasedEdgeClassification::NodeBasedEdgeClassification()
|
|||||||
}
|
}
|
||||||
|
|
||||||
inline NodeBasedEdge::NodeBasedEdge()
|
inline NodeBasedEdge::NodeBasedEdge()
|
||||||
: source(SPECIAL_NODEID), target(SPECIAL_NODEID), weight(0), duration(0), annotation_data(-1)
|
: source(SPECIAL_NODEID), target(SPECIAL_NODEID), weight(0), duration(0), distance(0),
|
||||||
|
annotation_data(-1)
|
||||||
{
|
{
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -145,11 +149,12 @@ inline NodeBasedEdge::NodeBasedEdge(NodeID source,
|
|||||||
NodeID target,
|
NodeID target,
|
||||||
EdgeWeight weight,
|
EdgeWeight weight,
|
||||||
EdgeDuration duration,
|
EdgeDuration duration,
|
||||||
|
EdgeDistance distance,
|
||||||
GeometryID geometry_id,
|
GeometryID geometry_id,
|
||||||
AnnotationID annotation_data,
|
AnnotationID annotation_data,
|
||||||
NodeBasedEdgeClassification flags)
|
NodeBasedEdgeClassification flags)
|
||||||
: source(source), target(target), weight(weight), duration(duration), geometry_id(geometry_id),
|
: source(source), target(target), weight(weight), duration(duration), distance(distance),
|
||||||
annotation_data(annotation_data), flags(flags)
|
geometry_id(geometry_id), annotation_data(annotation_data), flags(flags)
|
||||||
{
|
{
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -175,11 +180,18 @@ inline NodeBasedEdgeWithOSM::NodeBasedEdgeWithOSM(OSMNodeID source,
|
|||||||
OSMNodeID target,
|
OSMNodeID target,
|
||||||
EdgeWeight weight,
|
EdgeWeight weight,
|
||||||
EdgeDuration duration,
|
EdgeDuration duration,
|
||||||
|
EdgeDistance distance,
|
||||||
GeometryID geometry_id,
|
GeometryID geometry_id,
|
||||||
AnnotationID annotation_data,
|
AnnotationID annotation_data,
|
||||||
NodeBasedEdgeClassification flags)
|
NodeBasedEdgeClassification flags)
|
||||||
: NodeBasedEdge(
|
: NodeBasedEdge(SPECIAL_NODEID,
|
||||||
SPECIAL_NODEID, SPECIAL_NODEID, weight, duration, geometry_id, annotation_data, flags),
|
SPECIAL_NODEID,
|
||||||
|
weight,
|
||||||
|
duration,
|
||||||
|
distance,
|
||||||
|
geometry_id,
|
||||||
|
annotation_data,
|
||||||
|
flags),
|
||||||
osm_source_id(std::move(source)), osm_target_id(std::move(target))
|
osm_source_id(std::move(source)), osm_target_id(std::move(target))
|
||||||
{
|
{
|
||||||
}
|
}
|
||||||
@@ -189,12 +201,12 @@ inline NodeBasedEdgeWithOSM::NodeBasedEdgeWithOSM()
|
|||||||
{
|
{
|
||||||
}
|
}
|
||||||
|
|
||||||
static_assert(sizeof(extractor::NodeBasedEdge) == 28,
|
static_assert(sizeof(extractor::NodeBasedEdge) == 32,
|
||||||
"Size of extractor::NodeBasedEdge type is "
|
"Size of extractor::NodeBasedEdge type is "
|
||||||
"bigger than expected. This will influence "
|
"bigger than expected. This will influence "
|
||||||
"memory consumption.");
|
"memory consumption.");
|
||||||
|
|
||||||
} // ns extractor
|
} // namespace extractor
|
||||||
} // ns osrm
|
} // namespace osrm
|
||||||
|
|
||||||
#endif /* NODE_BASED_EDGE_HPP */
|
#endif /* NODE_BASED_EDGE_HPP */
|
||||||
|
|||||||
@@ -1064,6 +1064,46 @@ argumentsToTableParameter(const Nan::FunctionCallbackInfo<v8::Value> &args,
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (obj->Has(Nan::New("annotations").ToLocalChecked()))
|
||||||
|
{
|
||||||
|
v8::Local<v8::Value> annotations = obj->Get(Nan::New("annotations").ToLocalChecked());
|
||||||
|
if (annotations.IsEmpty())
|
||||||
|
return table_parameters_ptr();
|
||||||
|
|
||||||
|
if (!annotations->IsArray())
|
||||||
|
{
|
||||||
|
Nan::ThrowError(
|
||||||
|
"Annotations must an array containing 'duration' or 'distance', or both");
|
||||||
|
return table_parameters_ptr();
|
||||||
|
}
|
||||||
|
|
||||||
|
params->annotations = osrm::TableParameters::AnnotationsType::None;
|
||||||
|
|
||||||
|
v8::Local<v8::Array> annotations_array = v8::Local<v8::Array>::Cast(annotations);
|
||||||
|
for (std::size_t i = 0; i < annotations_array->Length(); ++i)
|
||||||
|
{
|
||||||
|
const Nan::Utf8String annotations_utf8str(annotations_array->Get(i));
|
||||||
|
std::string annotations_str{*annotations_utf8str,
|
||||||
|
*annotations_utf8str + annotations_utf8str.length()};
|
||||||
|
|
||||||
|
if (annotations_str == "duration")
|
||||||
|
{
|
||||||
|
params->annotations =
|
||||||
|
params->annotations | osrm::TableParameters::AnnotationsType::Duration;
|
||||||
|
}
|
||||||
|
else if (annotations_str == "distance")
|
||||||
|
{
|
||||||
|
params->annotations =
|
||||||
|
params->annotations | osrm::TableParameters::AnnotationsType::Distance;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
Nan::ThrowError("this 'annotations' param is not supported");
|
||||||
|
return table_parameters_ptr();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
return params;
|
return params;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -14,6 +14,8 @@
|
|||||||
#include <tbb/parallel_for.h>
|
#include <tbb/parallel_for.h>
|
||||||
#include <tbb/parallel_reduce.h>
|
#include <tbb/parallel_reduce.h>
|
||||||
|
|
||||||
|
#include <iostream>
|
||||||
|
|
||||||
#include <cstdint>
|
#include <cstdint>
|
||||||
|
|
||||||
#include <algorithm>
|
#include <algorithm>
|
||||||
@@ -43,6 +45,7 @@ splitBidirectionalEdges(const std::vector<extractor::EdgeBasedEdge> &edges)
|
|||||||
edge.data.turn_id,
|
edge.data.turn_id,
|
||||||
std::max(edge.data.weight, 1),
|
std::max(edge.data.weight, 1),
|
||||||
edge.data.duration,
|
edge.data.duration,
|
||||||
|
edge.data.distance,
|
||||||
edge.data.forward,
|
edge.data.forward,
|
||||||
edge.data.backward);
|
edge.data.backward);
|
||||||
|
|
||||||
@@ -51,6 +54,7 @@ splitBidirectionalEdges(const std::vector<extractor::EdgeBasedEdge> &edges)
|
|||||||
edge.data.turn_id,
|
edge.data.turn_id,
|
||||||
std::max(edge.data.weight, 1),
|
std::max(edge.data.weight, 1),
|
||||||
edge.data.duration,
|
edge.data.duration,
|
||||||
|
edge.data.distance,
|
||||||
edge.data.backward,
|
edge.data.backward,
|
||||||
edge.data.forward);
|
edge.data.forward);
|
||||||
}
|
}
|
||||||
@@ -196,7 +200,7 @@ inline DynamicEdgeBasedGraph LoadEdgeBasedGraph(const boost::filesystem::path &p
|
|||||||
return DynamicEdgeBasedGraph(number_of_edge_based_nodes, std::move(tidied), checksum);
|
return DynamicEdgeBasedGraph(number_of_edge_based_nodes, std::move(tidied), checksum);
|
||||||
}
|
}
|
||||||
|
|
||||||
} // ns partition
|
} // namespace partitioner
|
||||||
} // ns osrm
|
} // namespace osrm
|
||||||
|
|
||||||
#endif
|
#endif
|
||||||
|
|||||||
@@ -1,8 +1,6 @@
|
|||||||
#ifndef OSRM_PARTITIONER_SERILIZATION_HPP
|
#ifndef OSRM_PARTITIONER_SERILIZATION_HPP
|
||||||
#define OSRM_PARTITIONER_SERILIZATION_HPP
|
#define OSRM_PARTITIONER_SERILIZATION_HPP
|
||||||
|
|
||||||
#include "customizer/edge_based_graph.hpp"
|
|
||||||
|
|
||||||
#include "partitioner/serialization.hpp"
|
#include "partitioner/serialization.hpp"
|
||||||
|
|
||||||
#include "storage/io.hpp"
|
#include "storage/io.hpp"
|
||||||
@@ -14,39 +12,6 @@ namespace partitioner
|
|||||||
namespace files
|
namespace files
|
||||||
{
|
{
|
||||||
|
|
||||||
// reads .osrm.mldgr file
|
|
||||||
template <typename MultiLevelGraphT>
|
|
||||||
inline void readGraph(const boost::filesystem::path &path,
|
|
||||||
MultiLevelGraphT &graph,
|
|
||||||
std::uint32_t &connectivity_checksum)
|
|
||||||
{
|
|
||||||
static_assert(std::is_same<customizer::MultiLevelEdgeBasedGraphView, MultiLevelGraphT>::value ||
|
|
||||||
std::is_same<customizer::MultiLevelEdgeBasedGraph, MultiLevelGraphT>::value,
|
|
||||||
"");
|
|
||||||
|
|
||||||
storage::tar::FileReader reader{path, storage::tar::FileReader::VerifyFingerprint};
|
|
||||||
|
|
||||||
reader.ReadInto("/mld/connectivity_checksum", connectivity_checksum);
|
|
||||||
serialization::read(reader, "/mld/multilevelgraph", graph);
|
|
||||||
}
|
|
||||||
|
|
||||||
// writes .osrm.mldgr file
|
|
||||||
template <typename MultiLevelGraphT>
|
|
||||||
inline void writeGraph(const boost::filesystem::path &path,
|
|
||||||
const MultiLevelGraphT &graph,
|
|
||||||
const std::uint32_t connectivity_checksum)
|
|
||||||
{
|
|
||||||
static_assert(std::is_same<customizer::MultiLevelEdgeBasedGraphView, MultiLevelGraphT>::value ||
|
|
||||||
std::is_same<customizer::MultiLevelEdgeBasedGraph, MultiLevelGraphT>::value,
|
|
||||||
"");
|
|
||||||
|
|
||||||
storage::tar::FileWriter writer{path, storage::tar::FileWriter::GenerateFingerprint};
|
|
||||||
|
|
||||||
writer.WriteElementCount64("/mld/connectivity_checksum", 1);
|
|
||||||
writer.WriteFrom("/mld/connectivity_checksum", connectivity_checksum);
|
|
||||||
serialization::write(writer, "/mld/multilevelgraph", graph);
|
|
||||||
}
|
|
||||||
|
|
||||||
// read .osrm.partition file
|
// read .osrm.partition file
|
||||||
template <typename MultiLevelPartitionT>
|
template <typename MultiLevelPartitionT>
|
||||||
inline void readPartition(const boost::filesystem::path &path, MultiLevelPartitionT &mlp)
|
inline void readPartition(const boost::filesystem::path &path, MultiLevelPartitionT &mlp)
|
||||||
@@ -102,6 +67,35 @@ inline void writeCells(const boost::filesystem::path &path, CellStorageT &storag
|
|||||||
|
|
||||||
serialization::write(writer, "/mld/cellstorage", storage);
|
serialization::write(writer, "/mld/cellstorage", storage);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// reads .osrm.mldgr file
|
||||||
|
template <typename MultiLevelGraphT>
|
||||||
|
inline void readGraph(const boost::filesystem::path &path,
|
||||||
|
MultiLevelGraphT &graph,
|
||||||
|
std::uint32_t &connectivity_checksum)
|
||||||
|
{
|
||||||
|
static_assert(std::is_same<partitioner::MultiLevelEdgeBasedGraph, MultiLevelGraphT>::value, "");
|
||||||
|
|
||||||
|
storage::tar::FileReader reader{path, storage::tar::FileReader::VerifyFingerprint};
|
||||||
|
|
||||||
|
reader.ReadInto("/mld/connectivity_checksum", connectivity_checksum);
|
||||||
|
serialization::read(reader, "/mld/multilevelgraph", graph);
|
||||||
|
}
|
||||||
|
|
||||||
|
// writes .osrm.mldgr file
|
||||||
|
template <typename MultiLevelGraphT>
|
||||||
|
inline void writeGraph(const boost::filesystem::path &path,
|
||||||
|
const MultiLevelGraphT &graph,
|
||||||
|
const std::uint32_t connectivity_checksum)
|
||||||
|
{
|
||||||
|
static_assert(std::is_same<partitioner::MultiLevelEdgeBasedGraph, MultiLevelGraphT>::value, "");
|
||||||
|
|
||||||
|
storage::tar::FileWriter writer{path, storage::tar::FileWriter::GenerateFingerprint};
|
||||||
|
|
||||||
|
writer.WriteElementCount64("/mld/connectivity_checksum", 1);
|
||||||
|
writer.WriteFrom("/mld/connectivity_checksum", connectivity_checksum);
|
||||||
|
serialization::write(writer, "/mld/multilevelgraph", graph);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,6 +1,7 @@
|
|||||||
#ifndef OSRM_PARTITIONER_MULTI_LEVEL_GRAPH_HPP
|
#ifndef OSRM_PARTITIONER_MULTI_LEVEL_GRAPH_HPP
|
||||||
#define OSRM_PARTITIONER_MULTI_LEVEL_GRAPH_HPP
|
#define OSRM_PARTITIONER_MULTI_LEVEL_GRAPH_HPP
|
||||||
|
|
||||||
|
#include "partitioner/edge_based_graph.hpp"
|
||||||
#include "partitioner/multi_level_partition.hpp"
|
#include "partitioner/multi_level_partition.hpp"
|
||||||
|
|
||||||
#include "storage/shared_memory_ownership.hpp"
|
#include "storage/shared_memory_ownership.hpp"
|
||||||
@@ -42,6 +43,8 @@ class MultiLevelGraph : public util::StaticGraph<EdgeDataT, Ownership>
|
|||||||
template <typename T> using Vector = util::ViewOrVector<T, Ownership>;
|
template <typename T> using Vector = util::ViewOrVector<T, Ownership>;
|
||||||
|
|
||||||
public:
|
public:
|
||||||
|
using SuperT::SuperT;
|
||||||
|
|
||||||
// We limit each node to have 255 edges
|
// We limit each node to have 255 edges
|
||||||
// this is very generous, we could probably pack this
|
// this is very generous, we could probably pack this
|
||||||
using EdgeOffset = std::uint8_t;
|
using EdgeOffset = std::uint8_t;
|
||||||
@@ -146,6 +149,14 @@ class MultiLevelGraph : public util::StaticGraph<EdgeDataT, Ownership>
|
|||||||
return max_border_node_id;
|
return max_border_node_id;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
auto data() && // rvalue ref-qualifier is a safety-belt
|
||||||
|
{
|
||||||
|
return std::make_tuple(std::move(SuperT::node_array),
|
||||||
|
std::move(SuperT::edge_array),
|
||||||
|
std::move(node_to_edge_offset),
|
||||||
|
connectivity_checksum);
|
||||||
|
}
|
||||||
|
|
||||||
private:
|
private:
|
||||||
template <typename ContainerT>
|
template <typename ContainerT>
|
||||||
auto GetHighestBorderLevel(const MultiLevelPartition &mlp, const ContainerT &edges) const
|
auto GetHighestBorderLevel(const MultiLevelPartition &mlp, const ContainerT &edges) const
|
||||||
@@ -218,9 +229,13 @@ class MultiLevelGraph : public util::StaticGraph<EdgeDataT, Ownership>
|
|||||||
const std::string &name,
|
const std::string &name,
|
||||||
const MultiLevelGraph<EdgeDataT, Ownership> &graph);
|
const MultiLevelGraph<EdgeDataT, Ownership> &graph);
|
||||||
|
|
||||||
|
protected:
|
||||||
Vector<EdgeOffset> node_to_edge_offset;
|
Vector<EdgeOffset> node_to_edge_offset;
|
||||||
std::uint32_t connectivity_checksum;
|
std::uint32_t connectivity_checksum;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
using MultiLevelEdgeBasedGraph =
|
||||||
|
MultiLevelGraph<EdgeBasedGraphEdgeData, storage::Ownership::Container>;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -16,7 +16,7 @@ namespace partitioner
|
|||||||
struct PartitionerConfig final : storage::IOConfig
|
struct PartitionerConfig final : storage::IOConfig
|
||||||
{
|
{
|
||||||
PartitionerConfig()
|
PartitionerConfig()
|
||||||
: IOConfig({".osrm", ".osrm.fileIndex", ".osrm.ebg_nodes"},
|
: IOConfig({".osrm", ".osrm.fileIndex", ".osrm.ebg_nodes", ".osrm.enw"},
|
||||||
{".osrm.hsgr", ".osrm.cnbg"},
|
{".osrm.hsgr", ".osrm.cnbg"},
|
||||||
{".osrm.ebg",
|
{".osrm.ebg",
|
||||||
".osrm.cnbg",
|
".osrm.cnbg",
|
||||||
|
|||||||
@@ -19,26 +19,6 @@ namespace partitioner
|
|||||||
namespace serialization
|
namespace serialization
|
||||||
{
|
{
|
||||||
|
|
||||||
template <typename EdgeDataT, storage::Ownership Ownership>
|
|
||||||
inline void read(storage::tar::FileReader &reader,
|
|
||||||
const std::string &name,
|
|
||||||
MultiLevelGraph<EdgeDataT, Ownership> &graph)
|
|
||||||
{
|
|
||||||
storage::serialization::read(reader, name + "/node_array", graph.node_array);
|
|
||||||
storage::serialization::read(reader, name + "/edge_array", graph.edge_array);
|
|
||||||
storage::serialization::read(reader, name + "/node_to_edge_offset", graph.node_to_edge_offset);
|
|
||||||
}
|
|
||||||
|
|
||||||
template <typename EdgeDataT, storage::Ownership Ownership>
|
|
||||||
inline void write(storage::tar::FileWriter &writer,
|
|
||||||
const std::string &name,
|
|
||||||
const MultiLevelGraph<EdgeDataT, Ownership> &graph)
|
|
||||||
{
|
|
||||||
storage::serialization::write(writer, name + "/node_array", graph.node_array);
|
|
||||||
storage::serialization::write(writer, name + "/edge_array", graph.edge_array);
|
|
||||||
storage::serialization::write(writer, name + "/node_to_edge_offset", graph.node_to_edge_offset);
|
|
||||||
}
|
|
||||||
|
|
||||||
template <storage::Ownership Ownership>
|
template <storage::Ownership Ownership>
|
||||||
inline void read(storage::tar::FileReader &reader,
|
inline void read(storage::tar::FileReader &reader,
|
||||||
const std::string &name,
|
const std::string &name,
|
||||||
|
|||||||
@@ -22,11 +22,11 @@ namespace qi = boost::spirit::qi;
|
|||||||
|
|
||||||
template <typename Iterator = std::string::iterator,
|
template <typename Iterator = std::string::iterator,
|
||||||
typename Signature = void(engine::api::TableParameters &)>
|
typename Signature = void(engine::api::TableParameters &)>
|
||||||
struct TableParametersGrammar final : public BaseParametersGrammar<Iterator, Signature>
|
struct TableParametersGrammar : public BaseParametersGrammar<Iterator, Signature>
|
||||||
{
|
{
|
||||||
using BaseGrammar = BaseParametersGrammar<Iterator, Signature>;
|
using BaseGrammar = BaseParametersGrammar<Iterator, Signature>;
|
||||||
|
|
||||||
TableParametersGrammar() : BaseGrammar(root_rule)
|
TableParametersGrammar() : TableParametersGrammar(root_rule)
|
||||||
{
|
{
|
||||||
#ifdef BOOST_HAS_LONG_LONG
|
#ifdef BOOST_HAS_LONG_LONG
|
||||||
if (std::is_same<std::size_t, unsigned long long>::value)
|
if (std::is_same<std::size_t, unsigned long long>::value)
|
||||||
@@ -51,15 +51,35 @@ struct TableParametersGrammar final : public BaseParametersGrammar<Iterator, Sig
|
|||||||
table_rule = destinations_rule(qi::_r1) | sources_rule(qi::_r1);
|
table_rule = destinations_rule(qi::_r1) | sources_rule(qi::_r1);
|
||||||
|
|
||||||
root_rule = BaseGrammar::query_rule(qi::_r1) > -qi::lit(".json") >
|
root_rule = BaseGrammar::query_rule(qi::_r1) > -qi::lit(".json") >
|
||||||
-('?' > (table_rule(qi::_r1) | BaseGrammar::base_rule(qi::_r1)) % '&');
|
-('?' > (table_rule(qi::_r1) | base_rule(qi::_r1)) % '&');
|
||||||
}
|
}
|
||||||
|
|
||||||
|
TableParametersGrammar(qi::rule<Iterator, Signature> &root_rule_) : BaseGrammar(root_rule_)
|
||||||
|
{
|
||||||
|
using AnnotationsType = engine::api::TableParameters::AnnotationsType;
|
||||||
|
|
||||||
|
annotations.add("duration", AnnotationsType::Duration)("distance",
|
||||||
|
AnnotationsType::Distance);
|
||||||
|
|
||||||
|
annotations_list = annotations[qi::_val |= qi::_1] % ',';
|
||||||
|
|
||||||
|
base_rule = BaseGrammar::base_rule(qi::_r1) |
|
||||||
|
(qi::lit("annotations=") >
|
||||||
|
annotations_list[ph::bind(&engine::api::TableParameters::annotations,
|
||||||
|
qi::_r1) = qi::_1]);
|
||||||
|
}
|
||||||
|
|
||||||
|
protected:
|
||||||
|
qi::rule<Iterator, Signature> base_rule;
|
||||||
|
|
||||||
private:
|
private:
|
||||||
qi::rule<Iterator, Signature> root_rule;
|
qi::rule<Iterator, Signature> root_rule;
|
||||||
qi::rule<Iterator, Signature> table_rule;
|
qi::rule<Iterator, Signature> table_rule;
|
||||||
qi::rule<Iterator, Signature> sources_rule;
|
qi::rule<Iterator, Signature> sources_rule;
|
||||||
qi::rule<Iterator, Signature> destinations_rule;
|
qi::rule<Iterator, Signature> destinations_rule;
|
||||||
qi::rule<Iterator, std::size_t()> size_t_;
|
qi::rule<Iterator, std::size_t()> size_t_;
|
||||||
|
qi::symbols<char, engine::api::TableParameters::AnnotationsType> annotations;
|
||||||
|
qi::rule<Iterator, engine::api::TableParameters::AnnotationsType()> annotations_list;
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -46,33 +46,39 @@ class SharedDataIndex
|
|||||||
|
|
||||||
template <typename T> auto GetBlockPtr(const std::string &name) const
|
template <typename T> auto GetBlockPtr(const std::string &name) const
|
||||||
{
|
{
|
||||||
const auto index_iter = block_to_region.find(name);
|
const auto ®ion = GetBlockRegion(name);
|
||||||
const auto ®ion = regions[index_iter->second];
|
|
||||||
return region.layout.GetBlockPtr<T>(region.memory_ptr, name);
|
return region.layout.GetBlockPtr<T>(region.memory_ptr, name);
|
||||||
}
|
}
|
||||||
|
|
||||||
template <typename T> auto GetBlockPtr(const std::string &name)
|
template <typename T> auto GetBlockPtr(const std::string &name)
|
||||||
{
|
{
|
||||||
const auto index_iter = block_to_region.find(name);
|
const auto ®ion = GetBlockRegion(name);
|
||||||
const auto ®ion = regions[index_iter->second];
|
|
||||||
return region.layout.GetBlockPtr<T>(region.memory_ptr, name);
|
return region.layout.GetBlockPtr<T>(region.memory_ptr, name);
|
||||||
}
|
}
|
||||||
|
|
||||||
std::size_t GetBlockEntries(const std::string &name) const
|
std::size_t GetBlockEntries(const std::string &name) const
|
||||||
{
|
{
|
||||||
const auto index_iter = block_to_region.find(name);
|
const auto ®ion = GetBlockRegion(name);
|
||||||
const auto ®ion = regions[index_iter->second];
|
|
||||||
return region.layout.GetBlockEntries(name);
|
return region.layout.GetBlockEntries(name);
|
||||||
}
|
}
|
||||||
|
|
||||||
std::size_t GetBlockSize(const std::string &name) const
|
std::size_t GetBlockSize(const std::string &name) const
|
||||||
{
|
{
|
||||||
const auto index_iter = block_to_region.find(name);
|
const auto ®ion = GetBlockRegion(name);
|
||||||
const auto ®ion = regions[index_iter->second];
|
|
||||||
return region.layout.GetBlockSize(name);
|
return region.layout.GetBlockSize(name);
|
||||||
}
|
}
|
||||||
|
|
||||||
private:
|
private:
|
||||||
|
const AllocatedRegion &GetBlockRegion(const std::string &name) const
|
||||||
|
{
|
||||||
|
const auto index_iter = block_to_region.find(name);
|
||||||
|
if (index_iter == block_to_region.end())
|
||||||
|
{
|
||||||
|
throw util::exception("data block " + name + " not found " + SOURCE_REF);
|
||||||
|
}
|
||||||
|
return regions[index_iter->second];
|
||||||
|
}
|
||||||
|
|
||||||
std::vector<AllocatedRegion> regions;
|
std::vector<AllocatedRegion> regions;
|
||||||
std::unordered_map<std::string, std::uint32_t> block_to_region;
|
std::unordered_map<std::string, std::uint32_t> block_to_region;
|
||||||
};
|
};
|
||||||
|
|||||||
@@ -26,7 +26,7 @@ namespace serialization
|
|||||||
inline void read(io::BufferReader &reader, DataLayout &layout);
|
inline void read(io::BufferReader &reader, DataLayout &layout);
|
||||||
|
|
||||||
inline void write(io::BufferWriter &writer, const DataLayout &layout);
|
inline void write(io::BufferWriter &writer, const DataLayout &layout);
|
||||||
}
|
} // namespace serialization
|
||||||
|
|
||||||
namespace detail
|
namespace detail
|
||||||
{
|
{
|
||||||
@@ -52,7 +52,7 @@ inline std::string trimName(const std::string &name_prefix, const std::string &n
|
|||||||
return name;
|
return name;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
} // namespace detail
|
||||||
|
|
||||||
class DataLayout
|
class DataLayout
|
||||||
{
|
{
|
||||||
@@ -165,7 +165,7 @@ struct SharedRegion
|
|||||||
static constexpr const int MAX_NAME_LENGTH = 254;
|
static constexpr const int MAX_NAME_LENGTH = 254;
|
||||||
|
|
||||||
SharedRegion() : name{0}, timestamp{0} {}
|
SharedRegion() : name{0}, timestamp{0} {}
|
||||||
SharedRegion(const std::string &name_, std::uint64_t timestamp, std::uint8_t shm_key)
|
SharedRegion(const std::string &name_, std::uint64_t timestamp, std::uint16_t shm_key)
|
||||||
: name{0}, timestamp{timestamp}, shm_key{shm_key}
|
: name{0}, timestamp{timestamp}, shm_key{shm_key}
|
||||||
{
|
{
|
||||||
std::copy_n(name_.begin(), std::min<std::size_t>(MAX_NAME_LENGTH, name_.size()), name);
|
std::copy_n(name_.begin(), std::min<std::size_t>(MAX_NAME_LENGTH, name_.size()), name);
|
||||||
@@ -175,14 +175,14 @@ struct SharedRegion
|
|||||||
|
|
||||||
char name[MAX_NAME_LENGTH + 1];
|
char name[MAX_NAME_LENGTH + 1];
|
||||||
std::uint64_t timestamp;
|
std::uint64_t timestamp;
|
||||||
std::uint8_t shm_key;
|
std::uint16_t shm_key;
|
||||||
};
|
};
|
||||||
|
|
||||||
// Keeps a list of all shared regions in a fixed-sized struct
|
// Keeps a list of all shared regions in a fixed-sized struct
|
||||||
// for fast access and deserialization.
|
// for fast access and deserialization.
|
||||||
struct SharedRegionRegister
|
struct SharedRegionRegister
|
||||||
{
|
{
|
||||||
using RegionID = std::uint8_t;
|
using RegionID = std::uint16_t;
|
||||||
static constexpr const RegionID INVALID_REGION_ID = std::numeric_limits<RegionID>::max();
|
static constexpr const RegionID INVALID_REGION_ID = std::numeric_limits<RegionID>::max();
|
||||||
using ShmKey = decltype(SharedRegion::shm_key);
|
using ShmKey = decltype(SharedRegion::shm_key);
|
||||||
|
|
||||||
@@ -250,12 +250,11 @@ struct SharedRegionRegister
|
|||||||
|
|
||||||
void ReleaseKey(ShmKey key) { shm_key_in_use[key] = false; }
|
void ReleaseKey(ShmKey key) { shm_key_in_use[key] = false; }
|
||||||
|
|
||||||
static constexpr const std::uint8_t MAX_SHARED_REGIONS =
|
static constexpr const std::size_t MAX_SHARED_REGIONS = 512;
|
||||||
std::numeric_limits<RegionID>::max() - 1;
|
|
||||||
static_assert(MAX_SHARED_REGIONS < std::numeric_limits<RegionID>::max(),
|
static_assert(MAX_SHARED_REGIONS < std::numeric_limits<RegionID>::max(),
|
||||||
"Number of shared memory regions needs to be less than the region id size.");
|
"Number of shared memory regions needs to be less than the region id size.");
|
||||||
|
|
||||||
static constexpr const std::uint8_t MAX_SHM_KEYS = std::numeric_limits<std::uint8_t>::max() - 1;
|
static constexpr const std::size_t MAX_SHM_KEYS = MAX_SHARED_REGIONS * 2;
|
||||||
|
|
||||||
static constexpr const char *name = "osrm-region";
|
static constexpr const char *name = "osrm-region";
|
||||||
|
|
||||||
@@ -263,7 +262,7 @@ struct SharedRegionRegister
|
|||||||
std::array<SharedRegion, MAX_SHARED_REGIONS> regions;
|
std::array<SharedRegion, MAX_SHARED_REGIONS> regions;
|
||||||
std::array<bool, MAX_SHM_KEYS> shm_key_in_use;
|
std::array<bool, MAX_SHM_KEYS> shm_key_in_use;
|
||||||
};
|
};
|
||||||
}
|
} // namespace storage
|
||||||
}
|
} // namespace osrm
|
||||||
|
|
||||||
#endif /* SHARED_DATA_TYPE_HPP */
|
#endif /* SHARED_DATA_TYPE_HPP */
|
||||||
|
|||||||
@@ -34,10 +34,10 @@ namespace storage
|
|||||||
|
|
||||||
struct OSRMLockFile
|
struct OSRMLockFile
|
||||||
{
|
{
|
||||||
boost::filesystem::path operator()()
|
template <typename IdentifierT> boost::filesystem::path operator()(const IdentifierT &id)
|
||||||
{
|
{
|
||||||
boost::filesystem::path temp_dir = boost::filesystem::temp_directory_path();
|
boost::filesystem::path temp_dir = boost::filesystem::temp_directory_path();
|
||||||
boost::filesystem::path lock_file = temp_dir / "osrm.lock";
|
boost::filesystem::path lock_file = temp_dir / ("osrm-" + std::to_string(id) + ".lock");
|
||||||
return lock_file;
|
return lock_file;
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
@@ -93,7 +93,7 @@ class SharedMemory
|
|||||||
try
|
try
|
||||||
{
|
{
|
||||||
OSRMLockFile lock_file;
|
OSRMLockFile lock_file;
|
||||||
boost::interprocess::xsi_key key(lock_file().string().c_str(), id);
|
boost::interprocess::xsi_key key(lock_file(id).string().c_str(), id);
|
||||||
result = RegionExists(key);
|
result = RegionExists(key);
|
||||||
}
|
}
|
||||||
catch (...)
|
catch (...)
|
||||||
@@ -106,7 +106,7 @@ class SharedMemory
|
|||||||
template <typename IdentifierT> static bool Remove(const IdentifierT id)
|
template <typename IdentifierT> static bool Remove(const IdentifierT id)
|
||||||
{
|
{
|
||||||
OSRMLockFile lock_file;
|
OSRMLockFile lock_file;
|
||||||
boost::interprocess::xsi_key key(lock_file().string().c_str(), id);
|
boost::interprocess::xsi_key key(lock_file(id).string().c_str(), id);
|
||||||
return Remove(key);
|
return Remove(key);
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -287,10 +287,11 @@ class SharedMemory
|
|||||||
template <typename IdentifierT, typename LockFileT = OSRMLockFile>
|
template <typename IdentifierT, typename LockFileT = OSRMLockFile>
|
||||||
std::unique_ptr<SharedMemory> makeSharedMemory(const IdentifierT &id, const uint64_t size = 0)
|
std::unique_ptr<SharedMemory> makeSharedMemory(const IdentifierT &id, const uint64_t size = 0)
|
||||||
{
|
{
|
||||||
|
static_assert(sizeof(id) == sizeof(std::uint16_t), "Key type is not 16 bits");
|
||||||
try
|
try
|
||||||
{
|
{
|
||||||
LockFileT lock_file;
|
LockFileT lock_file;
|
||||||
if (!boost::filesystem::exists(lock_file()))
|
if (!boost::filesystem::exists(lock_file(id)))
|
||||||
{
|
{
|
||||||
if (0 == size)
|
if (0 == size)
|
||||||
{
|
{
|
||||||
@@ -298,10 +299,10 @@ std::unique_ptr<SharedMemory> makeSharedMemory(const IdentifierT &id, const uint
|
|||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
boost::filesystem::ofstream ofs(lock_file());
|
boost::filesystem::ofstream ofs(lock_file(id));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
return std::make_unique<SharedMemory>(lock_file(), id, size);
|
return std::make_unique<SharedMemory>(lock_file(id), id, size);
|
||||||
}
|
}
|
||||||
catch (const boost::interprocess::interprocess_exception &e)
|
catch (const boost::interprocess::interprocess_exception &e)
|
||||||
{
|
{
|
||||||
@@ -310,7 +311,7 @@ std::unique_ptr<SharedMemory> makeSharedMemory(const IdentifierT &id, const uint
|
|||||||
throw util::exception(e.what() + SOURCE_REF);
|
throw util::exception(e.what() + SOURCE_REF);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
} // namespace storage
|
||||||
}
|
} // namespace osrm
|
||||||
|
|
||||||
#endif // SHARED_MEMORY_HPP
|
#endif // SHARED_MEMORY_HPP
|
||||||
|
|||||||
@@ -33,7 +33,7 @@ template <class Lock> class InvertedLock
|
|||||||
InvertedLock(Lock &lock) : lock(lock) { lock.unlock(); }
|
InvertedLock(Lock &lock) : lock(lock) { lock.unlock(); }
|
||||||
~InvertedLock() { lock.lock(); }
|
~InvertedLock() { lock.lock(); }
|
||||||
};
|
};
|
||||||
}
|
} // namespace
|
||||||
|
|
||||||
// The shared monitor implementation based on a semaphore and mutex
|
// The shared monitor implementation based on a semaphore and mutex
|
||||||
template <typename Data> struct SharedMonitor
|
template <typename Data> struct SharedMonitor
|
||||||
@@ -117,6 +117,19 @@ template <typename Data> struct SharedMonitor
|
|||||||
#endif
|
#endif
|
||||||
|
|
||||||
static void remove() { bi::shared_memory_object::remove(Data::name); }
|
static void remove() { bi::shared_memory_object::remove(Data::name); }
|
||||||
|
static bool exists()
|
||||||
|
{
|
||||||
|
try
|
||||||
|
{
|
||||||
|
bi::shared_memory_object shmem_open =
|
||||||
|
bi::shared_memory_object(bi::open_only, Data::name, bi::read_only);
|
||||||
|
}
|
||||||
|
catch (const bi::interprocess_exception &exception)
|
||||||
|
{
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
private:
|
private:
|
||||||
#if USE_BOOST_INTERPROCESS_CONDITION
|
#if USE_BOOST_INTERPROCESS_CONDITION
|
||||||
@@ -133,7 +146,9 @@ template <typename Data> struct SharedMonitor
|
|||||||
// like two-turnstile reusable barrier or boost/interprocess/sync/spin/condition.hpp
|
// like two-turnstile reusable barrier or boost/interprocess/sync/spin/condition.hpp
|
||||||
// fail if a waiter is killed.
|
// fail if a waiter is killed.
|
||||||
|
|
||||||
static constexpr int buffer_size = 256;
|
// Buffer size needs to be large enough to hold all the semaphores for every
|
||||||
|
// listener you want to support.
|
||||||
|
static constexpr int buffer_size = 4096 * 4;
|
||||||
|
|
||||||
struct InternalData
|
struct InternalData
|
||||||
{
|
{
|
||||||
@@ -219,8 +234,8 @@ template <typename Data> struct SharedMonitor
|
|||||||
bi::shared_memory_object shmem;
|
bi::shared_memory_object shmem;
|
||||||
bi::mapped_region region;
|
bi::mapped_region region;
|
||||||
};
|
};
|
||||||
}
|
} // namespace storage
|
||||||
}
|
} // namespace osrm
|
||||||
|
|
||||||
#undef USE_BOOST_INTERPROCESS_CONDITION
|
#undef USE_BOOST_INTERPROCESS_CONDITION
|
||||||
|
|
||||||
|
|||||||
@@ -29,10 +29,8 @@ checkMTarError(int error_code, const boost::filesystem::path &filepath, const st
|
|||||||
case MTAR_ESUCCESS:
|
case MTAR_ESUCCESS:
|
||||||
return;
|
return;
|
||||||
case MTAR_EFAILURE:
|
case MTAR_EFAILURE:
|
||||||
throw util::RuntimeError(filepath.string() + " : " + name,
|
throw util::RuntimeError(
|
||||||
ErrorCode::FileIOError,
|
filepath.string() + " : " + name, ErrorCode::FileIOError, SOURCE_REF);
|
||||||
SOURCE_REF,
|
|
||||||
std::strerror(errno));
|
|
||||||
case MTAR_EOPENFAIL:
|
case MTAR_EOPENFAIL:
|
||||||
throw util::RuntimeError(filepath.string() + " : " + name,
|
throw util::RuntimeError(filepath.string() + " : " + name,
|
||||||
ErrorCode::FileOpenError,
|
ErrorCode::FileOpenError,
|
||||||
|
|||||||
@@ -330,9 +330,18 @@ inline auto make_multi_level_graph_view(const SharedDataIndex &index, const std:
|
|||||||
index, name + "/edge_array");
|
index, name + "/edge_array");
|
||||||
auto node_to_offset = make_vector_view<customizer::MultiLevelEdgeBasedGraphView::EdgeOffset>(
|
auto node_to_offset = make_vector_view<customizer::MultiLevelEdgeBasedGraphView::EdgeOffset>(
|
||||||
index, name + "/node_to_edge_offset");
|
index, name + "/node_to_edge_offset");
|
||||||
|
auto node_weights = make_vector_view<EdgeWeight>(index, name + "/node_weights");
|
||||||
|
auto node_durations = make_vector_view<EdgeDuration>(index, name + "/node_durations");
|
||||||
|
auto is_forward_edge = make_vector_view<bool>(index, name + "/is_forward_edge");
|
||||||
|
auto is_backward_edge = make_vector_view<bool>(index, name + "/is_backward_edge");
|
||||||
|
|
||||||
return customizer::MultiLevelEdgeBasedGraphView(
|
return customizer::MultiLevelEdgeBasedGraphView(std::move(node_list),
|
||||||
std::move(node_list), std::move(edge_list), std::move(node_to_offset));
|
std::move(edge_list),
|
||||||
|
std::move(node_to_offset),
|
||||||
|
std::move(node_weights),
|
||||||
|
std::move(node_durations),
|
||||||
|
std::move(is_forward_edge),
|
||||||
|
std::move(is_backward_edge));
|
||||||
}
|
}
|
||||||
|
|
||||||
inline auto make_maneuver_overrides_views(const SharedDataIndex &index, const std::string &name)
|
inline auto make_maneuver_overrides_views(const SharedDataIndex &index, const std::string &name)
|
||||||
|
|||||||
@@ -17,13 +17,15 @@ class Updater
|
|||||||
public:
|
public:
|
||||||
Updater(UpdaterConfig config_) : config(std::move(config_)) {}
|
Updater(UpdaterConfig config_) : config(std::move(config_)) {}
|
||||||
|
|
||||||
using NumNodesAndEdges =
|
EdgeID
|
||||||
std::tuple<EdgeID, std::vector<extractor::EdgeBasedEdge>, std::uint32_t>;
|
LoadAndUpdateEdgeExpandedGraph(std::vector<extractor::EdgeBasedEdge> &edge_based_edge_list,
|
||||||
NumNodesAndEdges LoadAndUpdateEdgeExpandedGraph() const;
|
std::vector<EdgeWeight> &node_weights,
|
||||||
|
std::uint32_t &connectivity_checksum) const;
|
||||||
|
|
||||||
EdgeID
|
EdgeID
|
||||||
LoadAndUpdateEdgeExpandedGraph(std::vector<extractor::EdgeBasedEdge> &edge_based_edge_list,
|
LoadAndUpdateEdgeExpandedGraph(std::vector<extractor::EdgeBasedEdge> &edge_based_edge_list,
|
||||||
std::vector<EdgeWeight> &node_weights,
|
std::vector<EdgeWeight> &node_weights,
|
||||||
|
std::vector<EdgeDuration> &node_durations, // TODO: to be deleted
|
||||||
std::uint32_t &connectivity_checksum) const;
|
std::uint32_t &connectivity_checksum) const;
|
||||||
|
|
||||||
private:
|
private:
|
||||||
|
|||||||
@@ -53,7 +53,8 @@ struct UpdaterConfig final : storage::IOConfig
|
|||||||
".osrm.geometry",
|
".osrm.geometry",
|
||||||
".osrm.fileIndex",
|
".osrm.fileIndex",
|
||||||
".osrm.properties",
|
".osrm.properties",
|
||||||
".osrm.restrictions"},
|
".osrm.restrictions",
|
||||||
|
".osrm.enw"},
|
||||||
{},
|
{},
|
||||||
{".osrm.datasource_names"}),
|
{".osrm.datasource_names"}),
|
||||||
valid_now(0)
|
valid_now(0)
|
||||||
|
|||||||
@@ -23,9 +23,6 @@ namespace detail
|
|||||||
{
|
{
|
||||||
const constexpr double DEGREE_TO_RAD = 0.017453292519943295769236907684886;
|
const constexpr double DEGREE_TO_RAD = 0.017453292519943295769236907684886;
|
||||||
const constexpr double RAD_TO_DEGREE = 1. / DEGREE_TO_RAD;
|
const constexpr double RAD_TO_DEGREE = 1. / DEGREE_TO_RAD;
|
||||||
// earth radius varies between 6,356.750-6,378.135 km (3,949.901-3,963.189mi)
|
|
||||||
// The IUGG value for the equatorial radius is 6378.137 km (3963.19 miles)
|
|
||||||
const constexpr long double EARTH_RADIUS = 6372797.560856;
|
|
||||||
|
|
||||||
inline double degToRad(const double degree)
|
inline double degToRad(const double degree)
|
||||||
{
|
{
|
||||||
@@ -43,6 +40,9 @@ inline double radToDeg(const double radian)
|
|||||||
//! Takes the squared euclidean distance of the input coordinates. Does not return meters!
|
//! Takes the squared euclidean distance of the input coordinates. Does not return meters!
|
||||||
std::uint64_t squaredEuclideanDistance(const Coordinate lhs, const Coordinate rhs);
|
std::uint64_t squaredEuclideanDistance(const Coordinate lhs, const Coordinate rhs);
|
||||||
|
|
||||||
|
double fccApproximateDistance(const Coordinate first_coordinate,
|
||||||
|
const Coordinate second_coordinate);
|
||||||
|
|
||||||
double haversineDistance(const Coordinate first_coordinate, const Coordinate second_coordinate);
|
double haversineDistance(const Coordinate first_coordinate, const Coordinate second_coordinate);
|
||||||
|
|
||||||
double greatCircleDistance(const Coordinate first_coordinate, const Coordinate second_coordinate);
|
double greatCircleDistance(const Coordinate first_coordinate, const Coordinate second_coordinate);
|
||||||
|
|||||||
+32
-12
@@ -1,9 +1,11 @@
|
|||||||
#ifndef OSRM_UTIL_DEBUG_HPP_
|
#ifndef OSRM_UTIL_DEBUG_HPP_
|
||||||
#define OSRM_UTIL_DEBUG_HPP_
|
#define OSRM_UTIL_DEBUG_HPP_
|
||||||
|
|
||||||
|
#include "extractor/edge_based_edge.hpp"
|
||||||
#include "extractor/node_data_container.hpp"
|
#include "extractor/node_data_container.hpp"
|
||||||
#include "extractor/query_node.hpp"
|
#include "extractor/query_node.hpp"
|
||||||
#include "guidance/intersection.hpp"
|
#include "guidance/intersection.hpp"
|
||||||
|
#include "guidance/turn_instruction.hpp"
|
||||||
#include "guidance/turn_lane_data.hpp"
|
#include "guidance/turn_lane_data.hpp"
|
||||||
#include "engine/guidance/route_step.hpp"
|
#include "engine/guidance/route_step.hpp"
|
||||||
#include "util/node_based_graph.hpp"
|
#include "util/node_based_graph.hpp"
|
||||||
@@ -22,10 +24,10 @@ namespace util
|
|||||||
inline std::ostream &operator<<(std::ostream &out, const Coordinate &coordinate)
|
inline std::ostream &operator<<(std::ostream &out, const Coordinate &coordinate)
|
||||||
{
|
{
|
||||||
out << std::setprecision(12) << "{" << toFloating(coordinate.lon) << ", "
|
out << std::setprecision(12) << "{" << toFloating(coordinate.lon) << ", "
|
||||||
<< toFloating(coordinate.lon) << "}";
|
<< toFloating(coordinate.lat) << "}";
|
||||||
return out;
|
return out;
|
||||||
}
|
}
|
||||||
}
|
} // namespace util
|
||||||
|
|
||||||
namespace engine
|
namespace engine
|
||||||
{
|
{
|
||||||
@@ -60,8 +62,8 @@ inline std::ostream &operator<<(std::ostream &out, const RouteStep &step)
|
|||||||
|
|
||||||
return out;
|
return out;
|
||||||
}
|
}
|
||||||
}
|
} // namespace guidance
|
||||||
}
|
} // namespace engine
|
||||||
|
|
||||||
namespace guidance
|
namespace guidance
|
||||||
{
|
{
|
||||||
@@ -74,7 +76,7 @@ inline std::ostream &operator<<(std::ostream &out, const ConnectedRoad &road)
|
|||||||
<< static_cast<std::int32_t>(road.lane_data_id) << "}";
|
<< static_cast<std::int32_t>(road.lane_data_id) << "}";
|
||||||
return out;
|
return out;
|
||||||
}
|
}
|
||||||
}
|
} // namespace guidance
|
||||||
|
|
||||||
namespace extractor
|
namespace extractor
|
||||||
{
|
{
|
||||||
@@ -93,7 +95,7 @@ inline std::ostream &operator<<(std::ostream &out, const IntersectionViewData &v
|
|||||||
<< " angle: " << view.angle << " bearing: " << view.perceived_bearing << "}";
|
<< " angle: " << view.angle << " bearing: " << view.perceived_bearing << "}";
|
||||||
return out;
|
return out;
|
||||||
}
|
}
|
||||||
}
|
} // namespace intersection
|
||||||
|
|
||||||
namespace TurnLaneType
|
namespace TurnLaneType
|
||||||
{
|
{
|
||||||
@@ -123,9 +125,9 @@ inline std::ostream &operator<<(std::ostream &out, const Mask lane_type)
|
|||||||
|
|
||||||
return out;
|
return out;
|
||||||
}
|
}
|
||||||
}
|
} // namespace TurnLaneType
|
||||||
}
|
} // namespace extractor
|
||||||
}
|
} // namespace osrm
|
||||||
|
|
||||||
namespace std
|
namespace std
|
||||||
{
|
{
|
||||||
@@ -145,7 +147,7 @@ inline std::ostream &operator<<(std::ostream &out,
|
|||||||
|
|
||||||
return out;
|
return out;
|
||||||
}
|
}
|
||||||
}
|
} // namespace std
|
||||||
|
|
||||||
namespace osrm
|
namespace osrm
|
||||||
{
|
{
|
||||||
@@ -184,8 +186,26 @@ inline std::ostream &operator<<(std::ostream &out, const LaneDataVector &turn_la
|
|||||||
|
|
||||||
return out;
|
return out;
|
||||||
}
|
}
|
||||||
}
|
} // namespace lanes
|
||||||
}
|
} // namespace guidance
|
||||||
|
|
||||||
|
namespace extractor
|
||||||
|
{
|
||||||
|
inline std::ostream &operator<<(std::ostream &out, const EdgeBasedEdge &edge)
|
||||||
|
{
|
||||||
|
out << " EdgeBasedEdge {";
|
||||||
|
out << " source " << edge.source << ", target: " << edge.target;
|
||||||
|
out << " EdgeBasedEdgeData data {";
|
||||||
|
out << " turn_id: " << edge.data.turn_id << ", weight: " << edge.data.weight;
|
||||||
|
out << " distance: " << edge.data.distance << ", duration: " << edge.data.duration;
|
||||||
|
out << " forward: " << (edge.data.forward == 0 ? "false" : "true")
|
||||||
|
<< ", backward: " << (edge.data.backward == 0 ? "false" : "true");
|
||||||
|
out << " }";
|
||||||
|
out << "}";
|
||||||
|
return out;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
} // namespace extractor
|
||||||
|
} // namespace osrm
|
||||||
|
|
||||||
#endif /*OSRM_ENGINE_GUIDANCE_DEBUG_HPP_*/
|
#endif /*OSRM_ENGINE_GUIDANCE_DEBUG_HPP_*/
|
||||||
|
|||||||
@@ -2,6 +2,8 @@
|
|||||||
#define DYNAMICGRAPH_HPP
|
#define DYNAMICGRAPH_HPP
|
||||||
|
|
||||||
#include "util/deallocating_vector.hpp"
|
#include "util/deallocating_vector.hpp"
|
||||||
|
#include "util/exception.hpp"
|
||||||
|
#include "util/exception_utils.hpp"
|
||||||
#include "util/integer_range.hpp"
|
#include "util/integer_range.hpp"
|
||||||
#include "util/permutation.hpp"
|
#include "util/permutation.hpp"
|
||||||
#include "util/typedefs.hpp"
|
#include "util/typedefs.hpp"
|
||||||
@@ -411,7 +413,12 @@ template <typename EdgeDataT> class DynamicGraph
|
|||||||
util::inplacePermutation(node_array.begin(), node_array.end(), old_to_new_node);
|
util::inplacePermutation(node_array.begin(), node_array.end(), old_to_new_node);
|
||||||
|
|
||||||
// Build up edge permutation
|
// Build up edge permutation
|
||||||
auto new_edge_index = 0;
|
if (edge_list.size() >= std::numeric_limits<EdgeID>::max())
|
||||||
|
{
|
||||||
|
throw util::exception("There are too many edges, OSRM only supports 2^32" + SOURCE_REF);
|
||||||
|
}
|
||||||
|
|
||||||
|
EdgeID new_edge_index = 0;
|
||||||
std::vector<EdgeID> old_to_new_edge(edge_list.size(), SPECIAL_EDGEID);
|
std::vector<EdgeID> old_to_new_edge(edge_list.size(), SPECIAL_EDGEID);
|
||||||
for (auto node : util::irange<NodeID>(0, number_of_nodes))
|
for (auto node : util::irange<NodeID>(0, number_of_nodes))
|
||||||
{
|
{
|
||||||
|
|||||||
@@ -0,0 +1,517 @@
|
|||||||
|
#ifndef IEEE754_HPP
|
||||||
|
#define IEEE754_HPP
|
||||||
|
/**
|
||||||
|
Copyright (C) 2014 Milo Yip
|
||||||
|
|
||||||
|
Imported from:
|
||||||
|
https://github.com/miloyip/dtoa-benchmark/blob/c4020c62754950d38a1aaaed2975b05b441d1e7d/src/milo/dtoa_milo.h
|
||||||
|
|
||||||
|
Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||||
|
of this software and associated documentation files (the "Software"), to deal
|
||||||
|
in the Software without restriction, including without limitation the rights
|
||||||
|
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||||
|
copies of the Software, and to permit persons to whom the Software is
|
||||||
|
furnished to do so, subject to the following conditions:
|
||||||
|
|
||||||
|
The above copyright notice and this permission notice shall be included in
|
||||||
|
all copies or substantial portions of the Software.
|
||||||
|
|
||||||
|
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||||
|
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||||
|
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||||
|
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||||
|
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||||
|
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
|
||||||
|
THE SOFTWARE.
|
||||||
|
**/
|
||||||
|
|
||||||
|
#include <assert.h>
|
||||||
|
#include <math.h>
|
||||||
|
|
||||||
|
#if defined(_MSC_VER)
|
||||||
|
#include "msinttypes/stdint.h"
|
||||||
|
#include <intrin.h>
|
||||||
|
#else
|
||||||
|
#include <stdint.h>
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#define UINT64_C2(h, l) ((static_cast<uint64_t>(h) << 32) | static_cast<uint64_t>(l))
|
||||||
|
|
||||||
|
namespace osrm
|
||||||
|
{
|
||||||
|
namespace util
|
||||||
|
{
|
||||||
|
namespace ieee754
|
||||||
|
{
|
||||||
|
|
||||||
|
struct DiyFp
|
||||||
|
{
|
||||||
|
DiyFp() {}
|
||||||
|
|
||||||
|
DiyFp(uint64_t f, int e) : f(f), e(e) {}
|
||||||
|
|
||||||
|
DiyFp(double d)
|
||||||
|
{
|
||||||
|
union {
|
||||||
|
double d;
|
||||||
|
uint64_t u64;
|
||||||
|
} u = {d};
|
||||||
|
|
||||||
|
int biased_e = (u.u64 & kDpExponentMask) >> kDpSignificandSize;
|
||||||
|
uint64_t significand = (u.u64 & kDpSignificandMask);
|
||||||
|
if (biased_e != 0)
|
||||||
|
{
|
||||||
|
f = significand + kDpHiddenBit;
|
||||||
|
e = biased_e - kDpExponentBias;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
f = significand;
|
||||||
|
e = kDpMinExponent + 1;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
DiyFp operator-(const DiyFp &rhs) const
|
||||||
|
{
|
||||||
|
assert(e == rhs.e);
|
||||||
|
assert(f >= rhs.f);
|
||||||
|
return DiyFp(f - rhs.f, e);
|
||||||
|
}
|
||||||
|
|
||||||
|
DiyFp operator*(const DiyFp &rhs) const
|
||||||
|
{
|
||||||
|
#if defined(_MSC_VER) && defined(_M_AMD64)
|
||||||
|
uint64_t h;
|
||||||
|
uint64_t l = _umul128(f, rhs.f, &h);
|
||||||
|
if (l & (uint64_t(1) << 63)) // rounding
|
||||||
|
h++;
|
||||||
|
return DiyFp(h, e + rhs.e + 64);
|
||||||
|
#elif (__GNUC__ > 4 || (__GNUC__ == 4 && __GNUC_MINOR__ >= 6)) && defined(__x86_64__)
|
||||||
|
unsigned __int128 p =
|
||||||
|
static_cast<unsigned __int128>(f) * static_cast<unsigned __int128>(rhs.f);
|
||||||
|
uint64_t h = p >> 64;
|
||||||
|
uint64_t l = static_cast<uint64_t>(p);
|
||||||
|
if (l & (uint64_t(1) << 63)) // rounding
|
||||||
|
h++;
|
||||||
|
return DiyFp(h, e + rhs.e + 64);
|
||||||
|
#else
|
||||||
|
const uint64_t M32 = 0xFFFFFFFF;
|
||||||
|
const uint64_t a = f >> 32;
|
||||||
|
const uint64_t b = f & M32;
|
||||||
|
const uint64_t c = rhs.f >> 32;
|
||||||
|
const uint64_t d = rhs.f & M32;
|
||||||
|
const uint64_t ac = a * c;
|
||||||
|
const uint64_t bc = b * c;
|
||||||
|
const uint64_t ad = a * d;
|
||||||
|
const uint64_t bd = b * d;
|
||||||
|
uint64_t tmp = (bd >> 32) + (ad & M32) + (bc & M32);
|
||||||
|
tmp += 1U << 31; /// mult_round
|
||||||
|
return DiyFp(ac + (ad >> 32) + (bc >> 32) + (tmp >> 32), e + rhs.e + 64);
|
||||||
|
#endif
|
||||||
|
}
|
||||||
|
|
||||||
|
DiyFp Normalize() const
|
||||||
|
{
|
||||||
|
#if defined(_MSC_VER) && defined(_M_AMD64)
|
||||||
|
unsigned long index;
|
||||||
|
_BitScanReverse64(&index, f);
|
||||||
|
return DiyFp(f << (63 - index), e - (63 - index));
|
||||||
|
#elif defined(__GNUC__)
|
||||||
|
int s = __builtin_clzll(f);
|
||||||
|
return DiyFp(f << s, e - s);
|
||||||
|
#else
|
||||||
|
DiyFp res = *this;
|
||||||
|
while (!(res.f & kDpHiddenBit))
|
||||||
|
{
|
||||||
|
res.f <<= 1;
|
||||||
|
res.e--;
|
||||||
|
}
|
||||||
|
res.f <<= (kDiySignificandSize - kDpSignificandSize - 1);
|
||||||
|
res.e = res.e - (kDiySignificandSize - kDpSignificandSize - 1);
|
||||||
|
return res;
|
||||||
|
#endif
|
||||||
|
}
|
||||||
|
|
||||||
|
DiyFp NormalizeBoundary() const
|
||||||
|
{
|
||||||
|
#if defined(_MSC_VER) && defined(_M_AMD64)
|
||||||
|
unsigned long index;
|
||||||
|
_BitScanReverse64(&index, f);
|
||||||
|
return DiyFp(f << (63 - index), e - (63 - index));
|
||||||
|
#else
|
||||||
|
DiyFp res = *this;
|
||||||
|
while (!(res.f & (kDpHiddenBit << 1)))
|
||||||
|
{
|
||||||
|
res.f <<= 1;
|
||||||
|
res.e--;
|
||||||
|
}
|
||||||
|
res.f <<= (kDiySignificandSize - kDpSignificandSize - 2);
|
||||||
|
res.e = res.e - (kDiySignificandSize - kDpSignificandSize - 2);
|
||||||
|
return res;
|
||||||
|
#endif
|
||||||
|
}
|
||||||
|
|
||||||
|
void NormalizedBoundaries(DiyFp *minus, DiyFp *plus) const
|
||||||
|
{
|
||||||
|
DiyFp pl = DiyFp((f << 1) + 1, e - 1).NormalizeBoundary();
|
||||||
|
DiyFp mi = (f == kDpHiddenBit) ? DiyFp((f << 2) - 1, e - 2) : DiyFp((f << 1) - 1, e - 1);
|
||||||
|
mi.f <<= mi.e - pl.e;
|
||||||
|
mi.e = pl.e;
|
||||||
|
*plus = pl;
|
||||||
|
*minus = mi;
|
||||||
|
}
|
||||||
|
|
||||||
|
static const int kDiySignificandSize = 64;
|
||||||
|
static const int kDpSignificandSize = 52;
|
||||||
|
static const int kDpExponentBias = 0x3FF + kDpSignificandSize;
|
||||||
|
static const int kDpMinExponent = -kDpExponentBias;
|
||||||
|
static const uint64_t kDpExponentMask = UINT64_C2(0x7FF00000, 0x00000000);
|
||||||
|
static const uint64_t kDpSignificandMask = UINT64_C2(0x000FFFFF, 0xFFFFFFFF);
|
||||||
|
static const uint64_t kDpHiddenBit = UINT64_C2(0x00100000, 0x00000000);
|
||||||
|
|
||||||
|
uint64_t f;
|
||||||
|
int e;
|
||||||
|
};
|
||||||
|
|
||||||
|
inline DiyFp GetCachedPower(int e, int *K)
|
||||||
|
{
|
||||||
|
// 10^-348, 10^-340, ..., 10^340
|
||||||
|
static const uint64_t kCachedPowers_F[] = {
|
||||||
|
UINT64_C2(0xfa8fd5a0, 0x081c0288), UINT64_C2(0xbaaee17f, 0xa23ebf76),
|
||||||
|
UINT64_C2(0x8b16fb20, 0x3055ac76), UINT64_C2(0xcf42894a, 0x5dce35ea),
|
||||||
|
UINT64_C2(0x9a6bb0aa, 0x55653b2d), UINT64_C2(0xe61acf03, 0x3d1a45df),
|
||||||
|
UINT64_C2(0xab70fe17, 0xc79ac6ca), UINT64_C2(0xff77b1fc, 0xbebcdc4f),
|
||||||
|
UINT64_C2(0xbe5691ef, 0x416bd60c), UINT64_C2(0x8dd01fad, 0x907ffc3c),
|
||||||
|
UINT64_C2(0xd3515c28, 0x31559a83), UINT64_C2(0x9d71ac8f, 0xada6c9b5),
|
||||||
|
UINT64_C2(0xea9c2277, 0x23ee8bcb), UINT64_C2(0xaecc4991, 0x4078536d),
|
||||||
|
UINT64_C2(0x823c1279, 0x5db6ce57), UINT64_C2(0xc2109436, 0x4dfb5637),
|
||||||
|
UINT64_C2(0x9096ea6f, 0x3848984f), UINT64_C2(0xd77485cb, 0x25823ac7),
|
||||||
|
UINT64_C2(0xa086cfcd, 0x97bf97f4), UINT64_C2(0xef340a98, 0x172aace5),
|
||||||
|
UINT64_C2(0xb23867fb, 0x2a35b28e), UINT64_C2(0x84c8d4df, 0xd2c63f3b),
|
||||||
|
UINT64_C2(0xc5dd4427, 0x1ad3cdba), UINT64_C2(0x936b9fce, 0xbb25c996),
|
||||||
|
UINT64_C2(0xdbac6c24, 0x7d62a584), UINT64_C2(0xa3ab6658, 0x0d5fdaf6),
|
||||||
|
UINT64_C2(0xf3e2f893, 0xdec3f126), UINT64_C2(0xb5b5ada8, 0xaaff80b8),
|
||||||
|
UINT64_C2(0x87625f05, 0x6c7c4a8b), UINT64_C2(0xc9bcff60, 0x34c13053),
|
||||||
|
UINT64_C2(0x964e858c, 0x91ba2655), UINT64_C2(0xdff97724, 0x70297ebd),
|
||||||
|
UINT64_C2(0xa6dfbd9f, 0xb8e5b88f), UINT64_C2(0xf8a95fcf, 0x88747d94),
|
||||||
|
UINT64_C2(0xb9447093, 0x8fa89bcf), UINT64_C2(0x8a08f0f8, 0xbf0f156b),
|
||||||
|
UINT64_C2(0xcdb02555, 0x653131b6), UINT64_C2(0x993fe2c6, 0xd07b7fac),
|
||||||
|
UINT64_C2(0xe45c10c4, 0x2a2b3b06), UINT64_C2(0xaa242499, 0x697392d3),
|
||||||
|
UINT64_C2(0xfd87b5f2, 0x8300ca0e), UINT64_C2(0xbce50864, 0x92111aeb),
|
||||||
|
UINT64_C2(0x8cbccc09, 0x6f5088cc), UINT64_C2(0xd1b71758, 0xe219652c),
|
||||||
|
UINT64_C2(0x9c400000, 0x00000000), UINT64_C2(0xe8d4a510, 0x00000000),
|
||||||
|
UINT64_C2(0xad78ebc5, 0xac620000), UINT64_C2(0x813f3978, 0xf8940984),
|
||||||
|
UINT64_C2(0xc097ce7b, 0xc90715b3), UINT64_C2(0x8f7e32ce, 0x7bea5c70),
|
||||||
|
UINT64_C2(0xd5d238a4, 0xabe98068), UINT64_C2(0x9f4f2726, 0x179a2245),
|
||||||
|
UINT64_C2(0xed63a231, 0xd4c4fb27), UINT64_C2(0xb0de6538, 0x8cc8ada8),
|
||||||
|
UINT64_C2(0x83c7088e, 0x1aab65db), UINT64_C2(0xc45d1df9, 0x42711d9a),
|
||||||
|
UINT64_C2(0x924d692c, 0xa61be758), UINT64_C2(0xda01ee64, 0x1a708dea),
|
||||||
|
UINT64_C2(0xa26da399, 0x9aef774a), UINT64_C2(0xf209787b, 0xb47d6b85),
|
||||||
|
UINT64_C2(0xb454e4a1, 0x79dd1877), UINT64_C2(0x865b8692, 0x5b9bc5c2),
|
||||||
|
UINT64_C2(0xc83553c5, 0xc8965d3d), UINT64_C2(0x952ab45c, 0xfa97a0b3),
|
||||||
|
UINT64_C2(0xde469fbd, 0x99a05fe3), UINT64_C2(0xa59bc234, 0xdb398c25),
|
||||||
|
UINT64_C2(0xf6c69a72, 0xa3989f5c), UINT64_C2(0xb7dcbf53, 0x54e9bece),
|
||||||
|
UINT64_C2(0x88fcf317, 0xf22241e2), UINT64_C2(0xcc20ce9b, 0xd35c78a5),
|
||||||
|
UINT64_C2(0x98165af3, 0x7b2153df), UINT64_C2(0xe2a0b5dc, 0x971f303a),
|
||||||
|
UINT64_C2(0xa8d9d153, 0x5ce3b396), UINT64_C2(0xfb9b7cd9, 0xa4a7443c),
|
||||||
|
UINT64_C2(0xbb764c4c, 0xa7a44410), UINT64_C2(0x8bab8eef, 0xb6409c1a),
|
||||||
|
UINT64_C2(0xd01fef10, 0xa657842c), UINT64_C2(0x9b10a4e5, 0xe9913129),
|
||||||
|
UINT64_C2(0xe7109bfb, 0xa19c0c9d), UINT64_C2(0xac2820d9, 0x623bf429),
|
||||||
|
UINT64_C2(0x80444b5e, 0x7aa7cf85), UINT64_C2(0xbf21e440, 0x03acdd2d),
|
||||||
|
UINT64_C2(0x8e679c2f, 0x5e44ff8f), UINT64_C2(0xd433179d, 0x9c8cb841),
|
||||||
|
UINT64_C2(0x9e19db92, 0xb4e31ba9), UINT64_C2(0xeb96bf6e, 0xbadf77d9),
|
||||||
|
UINT64_C2(0xaf87023b, 0x9bf0ee6b)};
|
||||||
|
static const int16_t kCachedPowers_E[] = {
|
||||||
|
-1220, -1193, -1166, -1140, -1113, -1087, -1060, -1034, -1007, -980, -954, -927, -901,
|
||||||
|
-874, -847, -821, -794, -768, -741, -715, -688, -661, -635, -608, -582, -555,
|
||||||
|
-529, -502, -475, -449, -422, -396, -369, -343, -316, -289, -263, -236, -210,
|
||||||
|
-183, -157, -130, -103, -77, -50, -24, 3, 30, 56, 83, 109, 136,
|
||||||
|
162, 189, 216, 242, 269, 295, 322, 348, 375, 402, 428, 455, 481,
|
||||||
|
508, 534, 561, 588, 614, 641, 667, 694, 720, 747, 774, 800, 827,
|
||||||
|
853, 880, 907, 933, 960, 986, 1013, 1039, 1066};
|
||||||
|
|
||||||
|
// int k = static_cast<int>(ceil((-61 - e) * 0.30102999566398114)) + 374;
|
||||||
|
double dk =
|
||||||
|
(-61 - e) * 0.30102999566398114 + 347; // dk must be positive, so can do ceiling in positive
|
||||||
|
int k = static_cast<int>(dk);
|
||||||
|
if (k != dk)
|
||||||
|
k++;
|
||||||
|
|
||||||
|
unsigned index = static_cast<unsigned>((k >> 3) + 1);
|
||||||
|
*K = -(-348 + static_cast<int>(index << 3)); // decimal exponent no need lookup table
|
||||||
|
|
||||||
|
assert(index < sizeof(kCachedPowers_F) / sizeof(kCachedPowers_F[0]));
|
||||||
|
return DiyFp(kCachedPowers_F[index], kCachedPowers_E[index]);
|
||||||
|
}
|
||||||
|
|
||||||
|
inline void
|
||||||
|
GrisuRound(char *buffer, int len, uint64_t delta, uint64_t rest, uint64_t ten_kappa, uint64_t wp_w)
|
||||||
|
{
|
||||||
|
while (rest < wp_w && delta - rest >= ten_kappa && (rest + ten_kappa < wp_w || /// closer
|
||||||
|
wp_w - rest > rest + ten_kappa - wp_w))
|
||||||
|
{
|
||||||
|
buffer[len - 1]--;
|
||||||
|
rest += ten_kappa;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
inline unsigned CountDecimalDigit32(uint32_t n)
|
||||||
|
{
|
||||||
|
// Simple pure C++ implementation was faster than __builtin_clz version in this situation.
|
||||||
|
if (n < 10)
|
||||||
|
return 1;
|
||||||
|
if (n < 100)
|
||||||
|
return 2;
|
||||||
|
if (n < 1000)
|
||||||
|
return 3;
|
||||||
|
if (n < 10000)
|
||||||
|
return 4;
|
||||||
|
if (n < 100000)
|
||||||
|
return 5;
|
||||||
|
if (n < 1000000)
|
||||||
|
return 6;
|
||||||
|
if (n < 10000000)
|
||||||
|
return 7;
|
||||||
|
if (n < 100000000)
|
||||||
|
return 8;
|
||||||
|
if (n < 1000000000)
|
||||||
|
return 9;
|
||||||
|
return 10;
|
||||||
|
}
|
||||||
|
|
||||||
|
inline void
|
||||||
|
DigitGen(const DiyFp &W, const DiyFp &Mp, uint64_t delta, char *buffer, int *len, int *K)
|
||||||
|
{
|
||||||
|
static const uint32_t kPow10[] = {
|
||||||
|
1, 10, 100, 1000, 10000, 100000, 1000000, 10000000, 100000000, 1000000000};
|
||||||
|
const DiyFp one(uint64_t(1) << -Mp.e, Mp.e);
|
||||||
|
const DiyFp wp_w = Mp - W;
|
||||||
|
uint32_t p1 = static_cast<uint32_t>(Mp.f >> -one.e);
|
||||||
|
uint64_t p2 = Mp.f & (one.f - 1);
|
||||||
|
int kappa = static_cast<int>(CountDecimalDigit32(p1));
|
||||||
|
*len = 0;
|
||||||
|
|
||||||
|
while (kappa > 0)
|
||||||
|
{
|
||||||
|
uint32_t d;
|
||||||
|
switch (kappa)
|
||||||
|
{
|
||||||
|
case 10:
|
||||||
|
d = p1 / 1000000000;
|
||||||
|
p1 %= 1000000000;
|
||||||
|
break;
|
||||||
|
case 9:
|
||||||
|
d = p1 / 100000000;
|
||||||
|
p1 %= 100000000;
|
||||||
|
break;
|
||||||
|
case 8:
|
||||||
|
d = p1 / 10000000;
|
||||||
|
p1 %= 10000000;
|
||||||
|
break;
|
||||||
|
case 7:
|
||||||
|
d = p1 / 1000000;
|
||||||
|
p1 %= 1000000;
|
||||||
|
break;
|
||||||
|
case 6:
|
||||||
|
d = p1 / 100000;
|
||||||
|
p1 %= 100000;
|
||||||
|
break;
|
||||||
|
case 5:
|
||||||
|
d = p1 / 10000;
|
||||||
|
p1 %= 10000;
|
||||||
|
break;
|
||||||
|
case 4:
|
||||||
|
d = p1 / 1000;
|
||||||
|
p1 %= 1000;
|
||||||
|
break;
|
||||||
|
case 3:
|
||||||
|
d = p1 / 100;
|
||||||
|
p1 %= 100;
|
||||||
|
break;
|
||||||
|
case 2:
|
||||||
|
d = p1 / 10;
|
||||||
|
p1 %= 10;
|
||||||
|
break;
|
||||||
|
case 1:
|
||||||
|
d = p1;
|
||||||
|
p1 = 0;
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
#if defined(_MSC_VER)
|
||||||
|
__assume(0);
|
||||||
|
#elif __GNUC__ > 4 || (__GNUC__ == 4 && __GNUC_MINOR__ >= 5)
|
||||||
|
__builtin_unreachable();
|
||||||
|
#else
|
||||||
|
d = 0;
|
||||||
|
#endif
|
||||||
|
}
|
||||||
|
if (d || *len)
|
||||||
|
buffer[(*len)++] = '0' + static_cast<char>(d);
|
||||||
|
kappa--;
|
||||||
|
uint64_t tmp = (static_cast<uint64_t>(p1) << -one.e) + p2;
|
||||||
|
if (tmp <= delta)
|
||||||
|
{
|
||||||
|
*K += kappa;
|
||||||
|
GrisuRound(
|
||||||
|
buffer, *len, delta, tmp, static_cast<uint64_t>(kPow10[kappa]) << -one.e, wp_w.f);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// kappa = 0
|
||||||
|
for (;;)
|
||||||
|
{
|
||||||
|
p2 *= 10;
|
||||||
|
delta *= 10;
|
||||||
|
char d = static_cast<char>(p2 >> -one.e);
|
||||||
|
if (d || *len)
|
||||||
|
buffer[(*len)++] = '0' + d;
|
||||||
|
p2 &= one.f - 1;
|
||||||
|
kappa--;
|
||||||
|
if (p2 < delta)
|
||||||
|
{
|
||||||
|
*K += kappa;
|
||||||
|
GrisuRound(buffer, *len, delta, p2, one.f, wp_w.f * kPow10[-kappa]);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
inline void Grisu2(double value, char *buffer, int *length, int *K)
|
||||||
|
{
|
||||||
|
const DiyFp v(value);
|
||||||
|
DiyFp w_m, w_p;
|
||||||
|
v.NormalizedBoundaries(&w_m, &w_p);
|
||||||
|
|
||||||
|
const DiyFp c_mk = GetCachedPower(w_p.e, K);
|
||||||
|
const DiyFp W = v.Normalize() * c_mk;
|
||||||
|
DiyFp Wp = w_p * c_mk;
|
||||||
|
DiyFp Wm = w_m * c_mk;
|
||||||
|
Wm.f++;
|
||||||
|
Wp.f--;
|
||||||
|
DigitGen(W, Wp, Wp.f - Wm.f, buffer, length, K);
|
||||||
|
}
|
||||||
|
|
||||||
|
inline const char *GetDigitsLut()
|
||||||
|
{
|
||||||
|
static const char cDigitsLut[200] = {
|
||||||
|
'0', '0', '0', '1', '0', '2', '0', '3', '0', '4', '0', '5', '0', '6', '0', '7', '0',
|
||||||
|
'8', '0', '9', '1', '0', '1', '1', '1', '2', '1', '3', '1', '4', '1', '5', '1', '6',
|
||||||
|
'1', '7', '1', '8', '1', '9', '2', '0', '2', '1', '2', '2', '2', '3', '2', '4', '2',
|
||||||
|
'5', '2', '6', '2', '7', '2', '8', '2', '9', '3', '0', '3', '1', '3', '2', '3', '3',
|
||||||
|
'3', '4', '3', '5', '3', '6', '3', '7', '3', '8', '3', '9', '4', '0', '4', '1', '4',
|
||||||
|
'2', '4', '3', '4', '4', '4', '5', '4', '6', '4', '7', '4', '8', '4', '9', '5', '0',
|
||||||
|
'5', '1', '5', '2', '5', '3', '5', '4', '5', '5', '5', '6', '5', '7', '5', '8', '5',
|
||||||
|
'9', '6', '0', '6', '1', '6', '2', '6', '3', '6', '4', '6', '5', '6', '6', '6', '7',
|
||||||
|
'6', '8', '6', '9', '7', '0', '7', '1', '7', '2', '7', '3', '7', '4', '7', '5', '7',
|
||||||
|
'6', '7', '7', '7', '8', '7', '9', '8', '0', '8', '1', '8', '2', '8', '3', '8', '4',
|
||||||
|
'8', '5', '8', '6', '8', '7', '8', '8', '8', '9', '9', '0', '9', '1', '9', '2', '9',
|
||||||
|
'3', '9', '4', '9', '5', '9', '6', '9', '7', '9', '8', '9', '9'};
|
||||||
|
return cDigitsLut;
|
||||||
|
}
|
||||||
|
|
||||||
|
inline void WriteExponent(int K, char *buffer)
|
||||||
|
{
|
||||||
|
if (K < 0)
|
||||||
|
{
|
||||||
|
*buffer++ = '-';
|
||||||
|
K = -K;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (K >= 100)
|
||||||
|
{
|
||||||
|
*buffer++ = '0' + static_cast<char>(K / 100);
|
||||||
|
K %= 100;
|
||||||
|
const char *d = GetDigitsLut() + K * 2;
|
||||||
|
*buffer++ = d[0];
|
||||||
|
*buffer++ = d[1];
|
||||||
|
}
|
||||||
|
else if (K >= 10)
|
||||||
|
{
|
||||||
|
const char *d = GetDigitsLut() + K * 2;
|
||||||
|
*buffer++ = d[0];
|
||||||
|
*buffer++ = d[1];
|
||||||
|
}
|
||||||
|
else
|
||||||
|
*buffer++ = '0' + static_cast<char>(K);
|
||||||
|
|
||||||
|
*buffer = '\0';
|
||||||
|
}
|
||||||
|
|
||||||
|
inline void Prettify(char *buffer, int length, int k)
|
||||||
|
{
|
||||||
|
const int kk = length + k; // 10^(kk-1) <= v < 10^kk
|
||||||
|
|
||||||
|
if (length <= kk && kk <= 21)
|
||||||
|
{
|
||||||
|
// 1234e7 -> 12340000000
|
||||||
|
for (int i = length; i < kk; i++)
|
||||||
|
buffer[i] = '0';
|
||||||
|
buffer[kk] = '.';
|
||||||
|
buffer[kk + 1] = '0';
|
||||||
|
buffer[kk + 2] = '\0';
|
||||||
|
}
|
||||||
|
else if (0 < kk && kk <= 21)
|
||||||
|
{
|
||||||
|
// 1234e-2 -> 12.34
|
||||||
|
memmove(&buffer[kk + 1], &buffer[kk], length - kk);
|
||||||
|
buffer[kk] = '.';
|
||||||
|
buffer[length + 1] = '\0';
|
||||||
|
}
|
||||||
|
else if (-6 < kk && kk <= 0)
|
||||||
|
{
|
||||||
|
// 1234e-6 -> 0.001234
|
||||||
|
const int offset = 2 - kk;
|
||||||
|
memmove(&buffer[offset], &buffer[0], length);
|
||||||
|
buffer[0] = '0';
|
||||||
|
buffer[1] = '.';
|
||||||
|
for (int i = 2; i < offset; i++)
|
||||||
|
buffer[i] = '0';
|
||||||
|
buffer[length + offset] = '\0';
|
||||||
|
}
|
||||||
|
else if (length == 1)
|
||||||
|
{
|
||||||
|
// 1e30
|
||||||
|
buffer[1] = 'e';
|
||||||
|
WriteExponent(kk - 1, &buffer[2]);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
// 1234e30 -> 1.234e33
|
||||||
|
memmove(&buffer[2], &buffer[1], length - 1);
|
||||||
|
buffer[1] = '.';
|
||||||
|
buffer[length + 1] = 'e';
|
||||||
|
WriteExponent(kk - 1, &buffer[0 + length + 2]);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
inline void dtoa_milo(double value, char *buffer)
|
||||||
|
{
|
||||||
|
// Not handling NaN and inf
|
||||||
|
assert(!isnan(value));
|
||||||
|
assert(!isinf(value));
|
||||||
|
|
||||||
|
if (value == 0)
|
||||||
|
{
|
||||||
|
buffer[0] = '0';
|
||||||
|
buffer[1] = '.';
|
||||||
|
buffer[2] = '0';
|
||||||
|
buffer[3] = '\0';
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
if (value < 0)
|
||||||
|
{
|
||||||
|
*buffer++ = '-';
|
||||||
|
value = -value;
|
||||||
|
}
|
||||||
|
int length, K;
|
||||||
|
Grisu2(value, buffer, &length, &K);
|
||||||
|
Prettify(buffer, length, K);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
} // namespace ieee754
|
||||||
|
} // namespace util
|
||||||
|
} // namespace osrm
|
||||||
|
|
||||||
|
#endif // IEEE754_HPP
|
||||||
@@ -5,6 +5,7 @@
|
|||||||
#define JSON_RENDERER_HPP
|
#define JSON_RENDERER_HPP
|
||||||
|
|
||||||
#include "util/cast.hpp"
|
#include "util/cast.hpp"
|
||||||
|
#include "util/ieee754.hpp"
|
||||||
#include "util/string_util.hpp"
|
#include "util/string_util.hpp"
|
||||||
|
|
||||||
#include "osrm/json_container.hpp"
|
#include "osrm/json_container.hpp"
|
||||||
@@ -21,6 +22,11 @@ namespace util
|
|||||||
namespace json
|
namespace json
|
||||||
{
|
{
|
||||||
|
|
||||||
|
namespace
|
||||||
|
{
|
||||||
|
constexpr int MAX_FLOAT_STRING_LENGTH = 256;
|
||||||
|
}
|
||||||
|
|
||||||
struct Renderer
|
struct Renderer
|
||||||
{
|
{
|
||||||
explicit Renderer(std::ostream &_out) : out(_out) {}
|
explicit Renderer(std::ostream &_out) : out(_out) {}
|
||||||
@@ -34,8 +40,31 @@ struct Renderer
|
|||||||
|
|
||||||
void operator()(const Number &number) const
|
void operator()(const Number &number) const
|
||||||
{
|
{
|
||||||
out.precision(10);
|
char buffer[MAX_FLOAT_STRING_LENGTH] = {'\0'};
|
||||||
out << number.value;
|
ieee754::dtoa_milo(number.value, buffer);
|
||||||
|
|
||||||
|
// Trucate to 10 decimal places
|
||||||
|
int pos = 0;
|
||||||
|
int decimalpos = 0;
|
||||||
|
while (decimalpos == 0 && pos < MAX_FLOAT_STRING_LENGTH && buffer[pos] != 0)
|
||||||
|
{
|
||||||
|
if (buffer[pos] == '.')
|
||||||
|
{
|
||||||
|
decimalpos = pos;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
++pos;
|
||||||
|
}
|
||||||
|
while (pos < MAX_FLOAT_STRING_LENGTH && buffer[pos] != 0)
|
||||||
|
{
|
||||||
|
if (pos - decimalpos == 10)
|
||||||
|
{
|
||||||
|
buffer[pos] = '\0';
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
++pos;
|
||||||
|
}
|
||||||
|
out << buffer;
|
||||||
}
|
}
|
||||||
|
|
||||||
void operator()(const Object &object) const
|
void operator()(const Object &object) const
|
||||||
|
|||||||
@@ -20,24 +20,27 @@ namespace util
|
|||||||
struct NodeBasedEdgeData
|
struct NodeBasedEdgeData
|
||||||
{
|
{
|
||||||
NodeBasedEdgeData()
|
NodeBasedEdgeData()
|
||||||
: weight(INVALID_EDGE_WEIGHT), duration(INVALID_EDGE_WEIGHT), geometry_id({0, false}),
|
: weight(INVALID_EDGE_WEIGHT), duration(INVALID_EDGE_WEIGHT),
|
||||||
reversed(false), annotation_data(-1)
|
distance(INVALID_EDGE_DISTANCE), geometry_id({0, false}), reversed(false),
|
||||||
|
annotation_data(-1)
|
||||||
{
|
{
|
||||||
}
|
}
|
||||||
|
|
||||||
NodeBasedEdgeData(EdgeWeight weight,
|
NodeBasedEdgeData(EdgeWeight weight,
|
||||||
EdgeWeight duration,
|
EdgeWeight duration,
|
||||||
|
EdgeDistance distance,
|
||||||
GeometryID geometry_id,
|
GeometryID geometry_id,
|
||||||
bool reversed,
|
bool reversed,
|
||||||
extractor::NodeBasedEdgeClassification flags,
|
extractor::NodeBasedEdgeClassification flags,
|
||||||
AnnotationID annotation_data)
|
AnnotationID annotation_data)
|
||||||
: weight(weight), duration(duration), geometry_id(geometry_id), reversed(reversed),
|
: weight(weight), duration(duration), distance(distance), geometry_id(geometry_id),
|
||||||
flags(flags), annotation_data(annotation_data)
|
reversed(reversed), flags(flags), annotation_data(annotation_data)
|
||||||
{
|
{
|
||||||
}
|
}
|
||||||
|
|
||||||
EdgeWeight weight;
|
EdgeWeight weight;
|
||||||
EdgeWeight duration;
|
EdgeWeight duration;
|
||||||
|
EdgeDistance distance;
|
||||||
GeometryID geometry_id;
|
GeometryID geometry_id;
|
||||||
bool reversed : 1;
|
bool reversed : 1;
|
||||||
extractor::NodeBasedEdgeClassification flags;
|
extractor::NodeBasedEdgeClassification flags;
|
||||||
@@ -80,18 +83,20 @@ NodeBasedDynamicGraphFromEdges(NodeID number_of_nodes,
|
|||||||
const extractor::NodeBasedEdge &input_edge) {
|
const extractor::NodeBasedEdge &input_edge) {
|
||||||
output_edge.data.weight = input_edge.weight;
|
output_edge.data.weight = input_edge.weight;
|
||||||
output_edge.data.duration = input_edge.duration;
|
output_edge.data.duration = input_edge.duration;
|
||||||
|
output_edge.data.distance = input_edge.distance;
|
||||||
output_edge.data.flags = input_edge.flags;
|
output_edge.data.flags = input_edge.flags;
|
||||||
output_edge.data.annotation_data = input_edge.annotation_data;
|
output_edge.data.annotation_data = input_edge.annotation_data;
|
||||||
|
|
||||||
BOOST_ASSERT(output_edge.data.weight > 0);
|
BOOST_ASSERT(output_edge.data.weight > 0);
|
||||||
BOOST_ASSERT(output_edge.data.duration > 0);
|
BOOST_ASSERT(output_edge.data.duration > 0);
|
||||||
|
BOOST_ASSERT(output_edge.data.distance > 0);
|
||||||
});
|
});
|
||||||
|
|
||||||
tbb::parallel_sort(edges_list.begin(), edges_list.end());
|
tbb::parallel_sort(edges_list.begin(), edges_list.end());
|
||||||
|
|
||||||
return NodeBasedDynamicGraph(number_of_nodes, edges_list);
|
return NodeBasedDynamicGraph(number_of_nodes, edges_list);
|
||||||
}
|
}
|
||||||
}
|
} // namespace util
|
||||||
}
|
} // namespace osrm
|
||||||
|
|
||||||
#endif // NODE_BASED_GRAPH_HPP
|
#endif // NODE_BASED_GRAPH_HPP
|
||||||
|
|||||||
@@ -226,12 +226,14 @@ class QueryHeap
|
|||||||
Data &GetData(NodeID node)
|
Data &GetData(NodeID node)
|
||||||
{
|
{
|
||||||
const auto index = node_index.peek_index(node);
|
const auto index = node_index.peek_index(node);
|
||||||
|
BOOST_ASSERT((int)index >= 0 && (int)index < (int)inserted_nodes.size());
|
||||||
return inserted_nodes[index].data;
|
return inserted_nodes[index].data;
|
||||||
}
|
}
|
||||||
|
|
||||||
Data const &GetData(NodeID node) const
|
Data const &GetData(NodeID node) const
|
||||||
{
|
{
|
||||||
const auto index = node_index.peek_index(node);
|
const auto index = node_index.peek_index(node);
|
||||||
|
BOOST_ASSERT((int)index >= 0 && (int)index < (int)inserted_nodes.size());
|
||||||
return inserted_nodes[index].data;
|
return inserted_nodes[index].data;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -312,7 +312,7 @@ class StaticGraph
|
|||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
// private:
|
protected:
|
||||||
NodeIterator number_of_nodes;
|
NodeIterator number_of_nodes;
|
||||||
EdgeIterator number_of_edges;
|
EdgeIterator number_of_edges;
|
||||||
|
|
||||||
|
|||||||
@@ -48,7 +48,7 @@ struct osm_way_id
|
|||||||
struct duplicated_node
|
struct duplicated_node
|
||||||
{
|
{
|
||||||
};
|
};
|
||||||
}
|
} // namespace tag
|
||||||
using OSMNodeID = osrm::Alias<std::uint64_t, tag::osm_node_id>;
|
using OSMNodeID = osrm::Alias<std::uint64_t, tag::osm_node_id>;
|
||||||
static_assert(std::is_pod<OSMNodeID>(), "OSMNodeID is not a valid alias");
|
static_assert(std::is_pod<OSMNodeID>(), "OSMNodeID is not a valid alias");
|
||||||
using OSMWayID = osrm::Alias<std::uint64_t, tag::osm_way_id>;
|
using OSMWayID = osrm::Alias<std::uint64_t, tag::osm_way_id>;
|
||||||
@@ -75,6 +75,7 @@ using NameID = std::uint32_t;
|
|||||||
using AnnotationID = std::uint32_t;
|
using AnnotationID = std::uint32_t;
|
||||||
using EdgeWeight = std::int32_t;
|
using EdgeWeight = std::int32_t;
|
||||||
using EdgeDuration = std::int32_t;
|
using EdgeDuration = std::int32_t;
|
||||||
|
using EdgeDistance = float;
|
||||||
using SegmentWeight = std::uint32_t;
|
using SegmentWeight = std::uint32_t;
|
||||||
using SegmentDuration = std::uint32_t;
|
using SegmentDuration = std::uint32_t;
|
||||||
using TurnPenalty = std::int16_t; // turn penalty in 100ms units
|
using TurnPenalty = std::int16_t; // turn penalty in 100ms units
|
||||||
@@ -112,7 +113,9 @@ static const SegmentWeight MAX_SEGMENT_WEIGHT = INVALID_SEGMENT_WEIGHT - 1;
|
|||||||
static const SegmentDuration MAX_SEGMENT_DURATION = INVALID_SEGMENT_DURATION - 1;
|
static const SegmentDuration MAX_SEGMENT_DURATION = INVALID_SEGMENT_DURATION - 1;
|
||||||
static const EdgeWeight INVALID_EDGE_WEIGHT = std::numeric_limits<EdgeWeight>::max();
|
static const EdgeWeight INVALID_EDGE_WEIGHT = std::numeric_limits<EdgeWeight>::max();
|
||||||
static const EdgeDuration MAXIMAL_EDGE_DURATION = std::numeric_limits<EdgeDuration>::max();
|
static const EdgeDuration MAXIMAL_EDGE_DURATION = std::numeric_limits<EdgeDuration>::max();
|
||||||
|
static const EdgeDistance MAXIMAL_EDGE_DISTANCE = std::numeric_limits<EdgeDistance>::max();
|
||||||
static const TurnPenalty INVALID_TURN_PENALTY = std::numeric_limits<TurnPenalty>::max();
|
static const TurnPenalty INVALID_TURN_PENALTY = std::numeric_limits<TurnPenalty>::max();
|
||||||
|
static const EdgeDistance INVALID_EDGE_DISTANCE = std::numeric_limits<EdgeDistance>::max();
|
||||||
|
|
||||||
// FIXME the bitfields we use require a reduced maximal duration, this should be kept consistent
|
// FIXME the bitfields we use require a reduced maximal duration, this should be kept consistent
|
||||||
// within the code base. For now we have to ensure that we don't case 30 bit to -1 and break any
|
// within the code base. For now we have to ensure that we don't case 30 bit to -1 and break any
|
||||||
|
|||||||
@@ -9,31 +9,6 @@ namespace util
|
|||||||
{
|
{
|
||||||
namespace vector_tile
|
namespace vector_tile
|
||||||
{
|
{
|
||||||
|
|
||||||
const constexpr std::uint32_t ID_TAG = 1;
|
|
||||||
const constexpr std::uint32_t NAME_TAG = 1;
|
|
||||||
const constexpr std::uint32_t FEATURE_TAG = 2;
|
|
||||||
const constexpr std::uint32_t LAYER_TAG = 3;
|
|
||||||
const constexpr std::uint32_t GEOMETRY_TAG = 3;
|
|
||||||
const constexpr std::uint32_t KEY_TAG = 3;
|
|
||||||
const constexpr std::uint32_t VARIANT_TAG = 4;
|
|
||||||
const constexpr std::uint32_t EXTENT_TAG = 5;
|
|
||||||
const constexpr std::uint32_t VERSION_TAG = 15;
|
|
||||||
|
|
||||||
const constexpr std::uint32_t FEATURE_ATTRIBUTES_TAG = 2;
|
|
||||||
const constexpr std::uint32_t FEATURE_GEOMETRIES_TAG = 4;
|
|
||||||
|
|
||||||
const constexpr std::uint32_t GEOMETRY_TYPE_POINT = 1;
|
|
||||||
const constexpr std::uint32_t GEOMETRY_TYPE_LINE = 2;
|
|
||||||
|
|
||||||
const constexpr std::uint32_t VARIANT_TYPE_STRING = 1;
|
|
||||||
const constexpr std::uint32_t VARIANT_TYPE_FLOAT = 2;
|
|
||||||
const constexpr std::uint32_t VARIANT_TYPE_DOUBLE = 3;
|
|
||||||
|
|
||||||
const constexpr std::uint32_t VARIANT_TYPE_UINT64 = 5;
|
|
||||||
const constexpr std::uint32_t VARIANT_TYPE_SINT64 = 6;
|
|
||||||
const constexpr std::uint32_t VARIANT_TYPE_BOOL = 7;
|
|
||||||
|
|
||||||
// Vector tiles are 4096 virtual pixels on each side
|
// Vector tiles are 4096 virtual pixels on each side
|
||||||
const constexpr double EXTENT = 4096.0;
|
const constexpr double EXTENT = 4096.0;
|
||||||
const constexpr double BUFFER = 128.0;
|
const constexpr double BUFFER = 128.0;
|
||||||
|
|||||||
+7
-1
@@ -1,6 +1,6 @@
|
|||||||
{
|
{
|
||||||
"name": "osrm",
|
"name": "osrm",
|
||||||
"version": "5.17.0-latest.1",
|
"version": "5.20.0-alpha.1",
|
||||||
"private": false,
|
"private": false,
|
||||||
"description": "The Open Source Routing Machine is a high performance routing engine written in C++14 designed to run on OpenStreetMap data.",
|
"description": "The Open Source Routing Machine is a high performance routing engine written in C++14 designed to run on OpenStreetMap data.",
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
@@ -38,19 +38,25 @@
|
|||||||
"node": ">=4.0.0"
|
"node": ">=4.0.0"
|
||||||
},
|
},
|
||||||
"devDependencies": {
|
"devDependencies": {
|
||||||
|
"ansi-escape-sequences": "^4.0.0",
|
||||||
"aws-sdk": "~2.0.31",
|
"aws-sdk": "~2.0.31",
|
||||||
"babel-plugin-transform-class-properties": "^6.24.1",
|
"babel-plugin-transform-class-properties": "^6.24.1",
|
||||||
"chalk": "^1.1.3",
|
"chalk": "^1.1.3",
|
||||||
|
"command-line-args": "^5.0.2",
|
||||||
|
"command-line-usage": "^5.0.4",
|
||||||
|
"csv-stringify": "^3.0.0",
|
||||||
"cucumber": "^1.2.1",
|
"cucumber": "^1.2.1",
|
||||||
"d3-queue": "^2.0.3",
|
"d3-queue": "^2.0.3",
|
||||||
"docbox": "^1.0.6",
|
"docbox": "^1.0.6",
|
||||||
"documentation": "^4.0.0-rc.1",
|
"documentation": "^4.0.0-rc.1",
|
||||||
"eslint": "^2.4.0",
|
"eslint": "^2.4.0",
|
||||||
"faucet": "^0.0.1",
|
"faucet": "^0.0.1",
|
||||||
|
"jsonpath": "^1.0.0",
|
||||||
"node-timeout": "0.0.4",
|
"node-timeout": "0.0.4",
|
||||||
"polyline": "^0.2.0",
|
"polyline": "^0.2.0",
|
||||||
"request": "^2.69.0",
|
"request": "^2.69.0",
|
||||||
"tape": "^4.7.0",
|
"tape": "^4.7.0",
|
||||||
|
"turf": "^3.0.14",
|
||||||
"xmlbuilder": "^4.2.1"
|
"xmlbuilder": "^4.2.1"
|
||||||
},
|
},
|
||||||
"bundleDependencies": [
|
"bundleDependencies": [
|
||||||
|
|||||||
+242
-161
@@ -38,20 +38,10 @@ function setup()
|
|||||||
mode.pushing_bike
|
mode.pushing_bike
|
||||||
},
|
},
|
||||||
|
|
||||||
barrier_whitelist = Set {
|
barrier_blacklist = Set {
|
||||||
'sump_buster',
|
'yes',
|
||||||
'bus_trap',
|
'wall',
|
||||||
'cycle_barrier',
|
'fence'
|
||||||
'bollard',
|
|
||||||
'entrance',
|
|
||||||
'cattle_grid',
|
|
||||||
'border_control',
|
|
||||||
'toll_booth',
|
|
||||||
'sally_port',
|
|
||||||
'gate',
|
|
||||||
'lift_gate',
|
|
||||||
'no',
|
|
||||||
'block'
|
|
||||||
},
|
},
|
||||||
|
|
||||||
access_tag_whitelist = Set {
|
access_tag_whitelist = Set {
|
||||||
@@ -109,11 +99,11 @@ function setup()
|
|||||||
-- reduce the driving speed by 30% for unsafe roads
|
-- reduce the driving speed by 30% for unsafe roads
|
||||||
-- only used for cyclability metric
|
-- only used for cyclability metric
|
||||||
unsafe_highway_list = {
|
unsafe_highway_list = {
|
||||||
primary = 0.7,
|
primary = 0.5,
|
||||||
secondary = 0.75,
|
secondary = 0.65,
|
||||||
tertiary = 0.8,
|
tertiary = 0.8,
|
||||||
primary_link = 0.7,
|
primary_link = 0.5,
|
||||||
secondary_link = 0.75,
|
secondary_link = 0.65,
|
||||||
tertiary_link = 0.8,
|
tertiary_link = 0.8,
|
||||||
},
|
},
|
||||||
|
|
||||||
@@ -193,6 +183,16 @@ function setup()
|
|||||||
sett = 10
|
sett = 10
|
||||||
},
|
},
|
||||||
|
|
||||||
|
classes = Sequence {
|
||||||
|
'ferry', 'tunnel'
|
||||||
|
},
|
||||||
|
|
||||||
|
-- Which classes should be excludable
|
||||||
|
-- This increases memory usage so its disabled by default.
|
||||||
|
excludable = Sequence {
|
||||||
|
-- Set {'ferry'}
|
||||||
|
},
|
||||||
|
|
||||||
tracktype_speeds = {
|
tracktype_speeds = {
|
||||||
},
|
},
|
||||||
|
|
||||||
@@ -235,7 +235,7 @@ function process_node(profile, node, result)
|
|||||||
else
|
else
|
||||||
local barrier = node:get_value_by_key("barrier")
|
local barrier = node:get_value_by_key("barrier")
|
||||||
if barrier and "" ~= barrier then
|
if barrier and "" ~= barrier then
|
||||||
if not profile.barrier_whitelist[barrier] then
|
if profile.barrier_blacklist[barrier] then
|
||||||
result.barrier = true
|
result.barrier = true
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
@@ -250,204 +250,237 @@ end
|
|||||||
|
|
||||||
function handle_bicycle_tags(profile,way,result,data)
|
function handle_bicycle_tags(profile,way,result,data)
|
||||||
-- initial routability check, filters out buildings, boundaries, etc
|
-- initial routability check, filters out buildings, boundaries, etc
|
||||||
local route = way:get_value_by_key("route")
|
data.route = way:get_value_by_key("route")
|
||||||
local man_made = way:get_value_by_key("man_made")
|
data.man_made = way:get_value_by_key("man_made")
|
||||||
local railway = way:get_value_by_key("railway")
|
data.railway = way:get_value_by_key("railway")
|
||||||
local amenity = way:get_value_by_key("amenity")
|
data.amenity = way:get_value_by_key("amenity")
|
||||||
local public_transport = way:get_value_by_key("public_transport")
|
data.public_transport = way:get_value_by_key("public_transport")
|
||||||
local bridge = way:get_value_by_key("bridge")
|
data.bridge = way:get_value_by_key("bridge")
|
||||||
|
|
||||||
if (not data.highway or data.highway == '') and
|
if (not data.highway or data.highway == '') and
|
||||||
(not route or route == '') and
|
(not data.route or data.route == '') and
|
||||||
(not profile.use_public_transport or not railway or railway=='') and
|
(not profile.use_public_transport or not data.railway or data.railway=='') and
|
||||||
(not amenity or amenity=='') and
|
(not data.amenity or data.amenity=='') and
|
||||||
(not man_made or man_made=='') and
|
(not data.man_made or data.man_made=='') and
|
||||||
(not public_transport or public_transport=='') and
|
(not data.public_transport or data.public_transport=='') and
|
||||||
(not bridge or bridge=='')
|
(not data.bridge or data.bridge=='')
|
||||||
then
|
then
|
||||||
return false
|
return false
|
||||||
end
|
end
|
||||||
|
|
||||||
-- access
|
-- access
|
||||||
local access = find_access_tag(way, profile.access_tags_hierarchy)
|
data.access = find_access_tag(way, profile.access_tags_hierarchy)
|
||||||
if access and profile.access_tag_blacklist[access] then
|
if data.access and profile.access_tag_blacklist[data.access] then
|
||||||
return false
|
return false
|
||||||
end
|
end
|
||||||
|
|
||||||
-- other tags
|
-- other tags
|
||||||
local junction = way:get_value_by_key("junction")
|
data.junction = way:get_value_by_key("junction")
|
||||||
local maxspeed = parse_maxspeed(way:get_value_by_key ( "maxspeed") )
|
data.maxspeed = parse_maxspeed(way:get_value_by_key ( "maxspeed") )
|
||||||
local maxspeed_forward = parse_maxspeed(way:get_value_by_key( "maxspeed:forward"))
|
data.maxspeed_forward = parse_maxspeed(way:get_value_by_key( "maxspeed:forward"))
|
||||||
local maxspeed_backward = parse_maxspeed(way:get_value_by_key( "maxspeed:backward"))
|
data.maxspeed_backward = parse_maxspeed(way:get_value_by_key( "maxspeed:backward"))
|
||||||
local barrier = way:get_value_by_key("barrier")
|
data.barrier = way:get_value_by_key("barrier")
|
||||||
local oneway = way:get_value_by_key("oneway")
|
data.oneway = way:get_value_by_key("oneway")
|
||||||
local oneway_bicycle = way:get_value_by_key("oneway:bicycle")
|
data.oneway_bicycle = way:get_value_by_key("oneway:bicycle")
|
||||||
local cycleway = way:get_value_by_key("cycleway")
|
data.cycleway = way:get_value_by_key("cycleway")
|
||||||
local cycleway_left = way:get_value_by_key("cycleway:left")
|
data.cycleway_left = way:get_value_by_key("cycleway:left")
|
||||||
local cycleway_right = way:get_value_by_key("cycleway:right")
|
data.cycleway_right = way:get_value_by_key("cycleway:right")
|
||||||
local duration = way:get_value_by_key("duration")
|
data.duration = way:get_value_by_key("duration")
|
||||||
local service = way:get_value_by_key("service")
|
data.service = way:get_value_by_key("service")
|
||||||
local foot = way:get_value_by_key("foot")
|
data.foot = way:get_value_by_key("foot")
|
||||||
local foot_forward = way:get_value_by_key("foot:forward")
|
data.foot_forward = way:get_value_by_key("foot:forward")
|
||||||
local foot_backward = way:get_value_by_key("foot:backward")
|
data.foot_backward = way:get_value_by_key("foot:backward")
|
||||||
local bicycle = way:get_value_by_key("bicycle")
|
data.bicycle = way:get_value_by_key("bicycle")
|
||||||
|
|
||||||
|
speed_handler(profile,way,result,data)
|
||||||
|
|
||||||
|
oneway_handler(profile,way,result,data)
|
||||||
|
|
||||||
|
cycleway_handler(profile,way,result,data)
|
||||||
|
|
||||||
|
bike_push_handler(profile,way,result,data)
|
||||||
|
|
||||||
|
|
||||||
local way_type_allows_pushing = false
|
-- maxspeed
|
||||||
|
limit( result, data.maxspeed, data.maxspeed_forward, data.maxspeed_backward )
|
||||||
|
|
||||||
|
-- not routable if no speed assigned
|
||||||
|
-- this avoid assertions in debug builds
|
||||||
|
if result.forward_speed <= 0 and result.duration <= 0 then
|
||||||
|
result.forward_mode = mode.inaccessible
|
||||||
|
end
|
||||||
|
if result.backward_speed <= 0 and result.duration <= 0 then
|
||||||
|
result.backward_mode = mode.inaccessible
|
||||||
|
end
|
||||||
|
|
||||||
|
safety_handler(profile,way,result,data)
|
||||||
|
end
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
function speed_handler(profile,way,result,data)
|
||||||
|
|
||||||
|
data.way_type_allows_pushing = false
|
||||||
|
|
||||||
-- speed
|
-- speed
|
||||||
local bridge_speed = profile.bridge_speeds[bridge]
|
local bridge_speed = profile.bridge_speeds[data.bridge]
|
||||||
if (bridge_speed and bridge_speed > 0) then
|
if (bridge_speed and bridge_speed > 0) then
|
||||||
data.highway = bridge
|
data.highway = data.bridge
|
||||||
if duration and durationIsValid(duration) then
|
if data.duration and durationIsValid(data.duration) then
|
||||||
result.duration = math.max( parseDuration(duration), 1 )
|
result.duration = math.max( parseDuration(data.duration), 1 )
|
||||||
end
|
end
|
||||||
result.forward_speed = bridge_speed
|
result.forward_speed = bridge_speed
|
||||||
result.backward_speed = bridge_speed
|
result.backward_speed = bridge_speed
|
||||||
way_type_allows_pushing = true
|
data.way_type_allows_pushing = true
|
||||||
elseif profile.route_speeds[route] then
|
elseif profile.route_speeds[data.route] then
|
||||||
-- ferries (doesn't cover routes tagged using relations)
|
-- ferries (doesn't cover routes tagged using relations)
|
||||||
result.forward_mode = mode.ferry
|
result.forward_mode = mode.ferry
|
||||||
result.backward_mode = mode.ferry
|
result.backward_mode = mode.ferry
|
||||||
if duration and durationIsValid(duration) then
|
if data.duration and durationIsValid(data.duration) then
|
||||||
result.duration = math.max( 1, parseDuration(duration) )
|
result.duration = math.max( 1, parseDuration(data.duration) )
|
||||||
else
|
else
|
||||||
result.forward_speed = profile.route_speeds[route]
|
result.forward_speed = profile.route_speeds[data.route]
|
||||||
result.backward_speed = profile.route_speeds[route]
|
result.backward_speed = profile.route_speeds[data.route]
|
||||||
end
|
end
|
||||||
-- railway platforms (old tagging scheme)
|
-- railway platforms (old tagging scheme)
|
||||||
elseif railway and profile.platform_speeds[railway] then
|
elseif data.railway and profile.platform_speeds[data.railway] then
|
||||||
result.forward_speed = profile.platform_speeds[railway]
|
result.forward_speed = profile.platform_speeds[data.railway]
|
||||||
result.backward_speed = profile.platform_speeds[railway]
|
result.backward_speed = profile.platform_speeds[data.railway]
|
||||||
way_type_allows_pushing = true
|
data.way_type_allows_pushing = true
|
||||||
-- public_transport platforms (new tagging platform)
|
-- public_transport platforms (new tagging platform)
|
||||||
elseif public_transport and profile.platform_speeds[public_transport] then
|
elseif data.public_transport and profile.platform_speeds[data.public_transport] then
|
||||||
result.forward_speed = profile.platform_speeds[public_transport]
|
result.forward_speed = profile.platform_speeds[data.public_transport]
|
||||||
result.backward_speed = profile.platform_speeds[public_transport]
|
result.backward_speed = profile.platform_speeds[data.public_transport]
|
||||||
way_type_allows_pushing = true
|
data.way_type_allows_pushing = true
|
||||||
-- railways
|
-- railways
|
||||||
elseif profile.use_public_transport and railway and profile.railway_speeds[railway] and profile.access_tag_whitelist[access] then
|
elseif profile.use_public_transport and data.railway and profile.railway_speeds[data.railway] and profile.access_tag_whitelist[data.access] then
|
||||||
result.forward_mode = mode.train
|
result.forward_mode = mode.train
|
||||||
result.backward_mode = mode.train
|
result.backward_mode = mode.train
|
||||||
result.forward_speed = profile.railway_speeds[railway]
|
result.forward_speed = profile.railway_speeds[data.railway]
|
||||||
result.backward_speed = profile.railway_speeds[railway]
|
result.backward_speed = profile.railway_speeds[data.railway]
|
||||||
elseif amenity and profile.amenity_speeds[amenity] then
|
elseif data.amenity and profile.amenity_speeds[data.amenity] then
|
||||||
-- parking areas
|
-- parking areas
|
||||||
result.forward_speed = profile.amenity_speeds[amenity]
|
result.forward_speed = profile.amenity_speeds[data.amenity]
|
||||||
result.backward_speed = profile.amenity_speeds[amenity]
|
result.backward_speed = profile.amenity_speeds[data.amenity]
|
||||||
way_type_allows_pushing = true
|
data.way_type_allows_pushing = true
|
||||||
elseif profile.bicycle_speeds[data.highway] then
|
elseif profile.bicycle_speeds[data.highway] then
|
||||||
-- regular ways
|
-- regular ways
|
||||||
result.forward_speed = profile.bicycle_speeds[data.highway]
|
result.forward_speed = profile.bicycle_speeds[data.highway]
|
||||||
result.backward_speed = profile.bicycle_speeds[data.highway]
|
result.backward_speed = profile.bicycle_speeds[data.highway]
|
||||||
way_type_allows_pushing = true
|
data.way_type_allows_pushing = true
|
||||||
elseif access and profile.access_tag_whitelist[access] then
|
elseif data.access and profile.access_tag_whitelist[data.access] then
|
||||||
-- unknown way, but valid access tag
|
-- unknown way, but valid access tag
|
||||||
result.forward_speed = profile.default_speed
|
result.forward_speed = profile.default_speed
|
||||||
result.backward_speed = profile.default_speed
|
result.backward_speed = profile.default_speed
|
||||||
way_type_allows_pushing = true
|
data.way_type_allows_pushing = true
|
||||||
end
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
function oneway_handler(profile,way,result,data)
|
||||||
-- oneway
|
-- oneway
|
||||||
local implied_oneway = junction == "roundabout" or junction == "circular" or data.highway == "motorway"
|
data.implied_oneway = data.junction == "roundabout" or data.junction == "circular" or data.highway == "motorway"
|
||||||
local reverse = false
|
data.reverse = false
|
||||||
|
|
||||||
if oneway_bicycle == "yes" or oneway_bicycle == "1" or oneway_bicycle == "true" then
|
if data.oneway_bicycle == "yes" or data.oneway_bicycle == "1" or data.oneway_bicycle == "true" then
|
||||||
result.backward_mode = mode.inaccessible
|
result.backward_mode = mode.inaccessible
|
||||||
elseif oneway_bicycle == "no" or oneway_bicycle == "0" or oneway_bicycle == "false" then
|
elseif data.oneway_bicycle == "no" or data.oneway_bicycle == "0" or data.oneway_bicycle == "false" then
|
||||||
-- prevent other cases
|
-- prevent other cases
|
||||||
elseif oneway_bicycle == "-1" then
|
elseif data.oneway_bicycle == "-1" then
|
||||||
result.forward_mode = mode.inaccessible
|
result.forward_mode = mode.inaccessible
|
||||||
reverse = true
|
data.reverse = true
|
||||||
elseif oneway == "yes" or oneway == "1" or oneway == "true" then
|
elseif data.oneway == "yes" or data.oneway == "1" or data.oneway == "true" then
|
||||||
result.backward_mode = mode.inaccessible
|
result.backward_mode = mode.inaccessible
|
||||||
elseif oneway == "no" or oneway == "0" or oneway == "false" then
|
elseif data.oneway == "no" or data.oneway == "0" or data.oneway == "false" then
|
||||||
-- prevent other cases
|
-- prevent other cases
|
||||||
elseif oneway == "-1" then
|
elseif data.oneway == "-1" then
|
||||||
result.forward_mode = mode.inaccessible
|
result.forward_mode = mode.inaccessible
|
||||||
reverse = true
|
data.reverse = true
|
||||||
elseif implied_oneway then
|
elseif data.implied_oneway then
|
||||||
result.backward_mode = mode.inaccessible
|
result.backward_mode = mode.inaccessible
|
||||||
end
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
function cycleway_handler(profile,way,result,data)
|
||||||
-- cycleway
|
-- cycleway
|
||||||
local has_cycleway_forward = false
|
data.has_cycleway_forward = false
|
||||||
local has_cycleway_backward = false
|
data.has_cycleway_backward = false
|
||||||
local is_oneway = result.forward_mode ~= mode.inaccessible and result.backward_mode ~= mode.inaccessible and not implied_oneway
|
data.is_twoway = result.forward_mode ~= mode.inaccessible and result.backward_mode ~= mode.inaccessible and not data.implied_oneway
|
||||||
|
|
||||||
-- cycleways on normal roads
|
-- cycleways on normal roads
|
||||||
if is_oneway then
|
if data.is_twoway then
|
||||||
if cycleway and profile.cycleway_tags[cycleway] then
|
if data.cycleway and profile.cycleway_tags[data.cycleway] then
|
||||||
has_cycleway_backward = true
|
data.has_cycleway_backward = true
|
||||||
has_cycleway_forward = true
|
data.has_cycleway_forward = true
|
||||||
end
|
end
|
||||||
if (cycleway_right and profile.cycleway_tags[cycleway_right]) or (cycleway_left and profile.opposite_cycleway_tags[cycleway_left]) then
|
if (data.cycleway_right and profile.cycleway_tags[data.cycleway_right]) or (data.cycleway_left and profile.opposite_cycleway_tags[data.cycleway_left]) then
|
||||||
has_cycleway_forward = true
|
data.has_cycleway_forward = true
|
||||||
end
|
end
|
||||||
if (cycleway_left and profile.cycleway_tags[cycleway_left]) or (cycleway_right and profile.opposite_cycleway_tags[cycleway_right]) then
|
if (data.cycleway_left and profile.cycleway_tags[data.cycleway_left]) or (data.cycleway_right and profile.opposite_cycleway_tags[data.cycleway_right]) then
|
||||||
has_cycleway_backward = true
|
data.has_cycleway_backward = true
|
||||||
end
|
end
|
||||||
else
|
else
|
||||||
local has_twoway_cycleway = (cycleway and profile.opposite_cycleway_tags[cycleway]) or (cycleway_right and profile.opposite_cycleway_tags[cycleway_right]) or (cycleway_left and profile.opposite_cycleway_tags[cycleway_left])
|
local has_twoway_cycleway = (data.cycleway and profile.opposite_cycleway_tags[data.cycleway]) or (data.cycleway_right and profile.opposite_cycleway_tags[data.cycleway_right]) or (data.cycleway_left and profile.opposite_cycleway_tags[data.cycleway_left])
|
||||||
local has_opposite_cycleway = (cycleway_left and profile.opposite_cycleway_tags[cycleway_left]) or (cycleway_right and profile.opposite_cycleway_tags[cycleway_right])
|
local has_opposite_cycleway = (data.cycleway_left and profile.opposite_cycleway_tags[data.cycleway_left]) or (data.cycleway_right and profile.opposite_cycleway_tags[data.cycleway_right])
|
||||||
local has_oneway_cycleway = (cycleway and profile.cycleway_tags[cycleway]) or (cycleway_right and profile.cycleway_tags[cycleway_right]) or (cycleway_left and profile.cycleway_tags[cycleway_left])
|
local has_oneway_cycleway = (data.cycleway and profile.cycleway_tags[data.cycleway]) or (data.cycleway_right and profile.cycleway_tags[data.cycleway_right]) or (data.cycleway_left and profile.cycleway_tags[data.cycleway_left])
|
||||||
|
|
||||||
-- set cycleway even though it is an one-way if opposite is tagged
|
-- set cycleway even though it is an one-way if opposite is tagged
|
||||||
if has_twoway_cycleway then
|
if has_twoway_cycleway then
|
||||||
has_cycleway_backward = true
|
data.has_cycleway_backward = true
|
||||||
has_cycleway_forward = true
|
data.has_cycleway_forward = true
|
||||||
elseif has_opposite_cycleway then
|
elseif has_opposite_cycleway then
|
||||||
if not reverse then
|
if not data.reverse then
|
||||||
has_cycleway_backward = true
|
data.has_cycleway_backward = true
|
||||||
else
|
else
|
||||||
has_cycleway_forward = true
|
data.has_cycleway_forward = true
|
||||||
end
|
end
|
||||||
elseif has_oneway_cycleway then
|
elseif has_oneway_cycleway then
|
||||||
if not reverse then
|
if not data.reverse then
|
||||||
has_cycleway_forward = true
|
data.has_cycleway_forward = true
|
||||||
else
|
else
|
||||||
has_cycleway_backward = true
|
data.has_cycleway_backward = true
|
||||||
end
|
end
|
||||||
|
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
if has_cycleway_backward then
|
if data.has_cycleway_backward then
|
||||||
result.backward_mode = mode.cycling
|
result.backward_mode = mode.cycling
|
||||||
result.backward_speed = profile.bicycle_speeds["cycleway"]
|
result.backward_speed = profile.bicycle_speeds["cycleway"]
|
||||||
end
|
end
|
||||||
|
|
||||||
if has_cycleway_forward then
|
if data.has_cycleway_forward then
|
||||||
result.forward_mode = mode.cycling
|
result.forward_mode = mode.cycling
|
||||||
result.forward_speed = profile.bicycle_speeds["cycleway"]
|
result.forward_speed = profile.bicycle_speeds["cycleway"]
|
||||||
end
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
function bike_push_handler(profile,way,result,data)
|
||||||
-- pushing bikes - if no other mode found
|
-- pushing bikes - if no other mode found
|
||||||
if result.forward_mode == mode.inaccessible or result.backward_mode == mode.inaccessible or
|
if result.forward_mode == mode.inaccessible or result.backward_mode == mode.inaccessible or
|
||||||
result.forward_speed == -1 or result.backward_speed == -1 then
|
result.forward_speed == -1 or result.backward_speed == -1 then
|
||||||
if foot ~= 'no' then
|
if data.foot ~= 'no' then
|
||||||
local push_forward_speed = nil
|
local push_forward_speed = nil
|
||||||
local push_backward_speed = nil
|
local push_backward_speed = nil
|
||||||
|
|
||||||
if profile.pedestrian_speeds[data.highway] then
|
if profile.pedestrian_speeds[data.highway] then
|
||||||
push_forward_speed = profile.pedestrian_speeds[data.highway]
|
push_forward_speed = profile.pedestrian_speeds[data.highway]
|
||||||
push_backward_speed = profile.pedestrian_speeds[data.highway]
|
push_backward_speed = profile.pedestrian_speeds[data.highway]
|
||||||
elseif man_made and profile.man_made_speeds[man_made] then
|
elseif data.man_made and profile.man_made_speeds[data.man_made] then
|
||||||
push_forward_speed = profile.man_made_speeds[man_made]
|
push_forward_speed = profile.man_made_speeds[data.man_made]
|
||||||
push_backward_speed = profile.man_made_speeds[man_made]
|
push_backward_speed = profile.man_made_speeds[data.man_made]
|
||||||
else
|
else
|
||||||
if foot == 'yes' then
|
if data.foot == 'yes' then
|
||||||
push_forward_speed = profile.walking_speed
|
push_forward_speed = profile.walking_speed
|
||||||
if not implied_oneway then
|
if not data.implied_oneway then
|
||||||
push_backward_speed = profile.walking_speed
|
push_backward_speed = profile.walking_speed
|
||||||
end
|
end
|
||||||
elseif foot_forward == 'yes' then
|
elseif data.foot_forward == 'yes' then
|
||||||
push_forward_speed = profile.walking_speed
|
push_forward_speed = profile.walking_speed
|
||||||
elseif foot_backward == 'yes' then
|
elseif data.foot_backward == 'yes' then
|
||||||
push_backward_speed = profile.walking_speed
|
push_backward_speed = profile.walking_speed
|
||||||
elseif way_type_allows_pushing then
|
elseif data.way_type_allows_pushing then
|
||||||
push_forward_speed = profile.walking_speed
|
push_forward_speed = profile.walking_speed
|
||||||
if not implied_oneway then
|
if not data.implied_oneway then
|
||||||
push_backward_speed = profile.walking_speed
|
push_backward_speed = profile.walking_speed
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
@@ -466,65 +499,77 @@ function handle_bicycle_tags(profile,way,result,data)
|
|||||||
|
|
||||||
end
|
end
|
||||||
|
|
||||||
|
|
||||||
-- dismount
|
-- dismount
|
||||||
if bicycle == "dismount" then
|
if data.bicycle == "dismount" then
|
||||||
result.forward_mode = mode.pushing_bike
|
result.forward_mode = mode.pushing_bike
|
||||||
result.backward_mode = mode.pushing_bike
|
result.backward_mode = mode.pushing_bike
|
||||||
result.forward_speed = profile.walking_speed
|
result.forward_speed = profile.walking_speed
|
||||||
result.backward_speed = profile.walking_speed
|
result.backward_speed = profile.walking_speed
|
||||||
end
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
function safety_handler(profile,way,result,data)
|
||||||
|
|
||||||
-- maxspeed
|
|
||||||
limit( result, maxspeed, maxspeed_forward, maxspeed_backward )
|
|
||||||
|
|
||||||
|
|
||||||
-- not routable if no speed assigned
|
|
||||||
-- this avoid assertions in debug builds
|
|
||||||
if result.forward_speed <= 0 and result.duration <= 0 then
|
|
||||||
result.forward_mode = mode.inaccessible
|
|
||||||
end
|
|
||||||
if result.backward_speed <= 0 and result.duration <= 0 then
|
|
||||||
result.backward_mode = mode.inaccessible
|
|
||||||
end
|
|
||||||
|
|
||||||
|
|
||||||
-- convert duration into cyclability
|
-- convert duration into cyclability
|
||||||
if profile.properties.weight_name == 'cyclability' then
|
if profile.properties.weight_name == 'cyclability' then
|
||||||
local safety_penalty = profile.unsafe_highway_list[data.highway] or 1.
|
local safety_penalty = profile.unsafe_highway_list[data.highway] or 1.
|
||||||
local is_unsafe = safety_penalty < 1
|
local is_unsafe = safety_penalty < 1
|
||||||
local forward_is_unsafe = is_unsafe and not has_cycleway_forward
|
|
||||||
local backward_is_unsafe = is_unsafe and not has_cycleway_backward
|
|
||||||
local is_undesireable = data.highway == "service" and profile.service_penalties[service]
|
|
||||||
local forward_penalty = 1.
|
|
||||||
local backward_penalty = 1.
|
|
||||||
if forward_is_unsafe then
|
|
||||||
forward_penalty = math.min(forward_penalty, safety_penalty)
|
|
||||||
end
|
|
||||||
if backward_is_unsafe then
|
|
||||||
backward_penalty = math.min(backward_penalty, safety_penalty)
|
|
||||||
end
|
|
||||||
|
|
||||||
if is_undesireable then
|
-- primaries that are one ways are probably huge primaries where the lanes need to be separated
|
||||||
forward_penalty = math.min(forward_penalty, profile.service_penalties[service])
|
if is_unsafe and data.highway == 'primary' and not data.is_twoway then
|
||||||
backward_penalty = math.min(backward_penalty, profile.service_penalties[service])
|
safety_penalty = safety_penalty * 0.5
|
||||||
end
|
end
|
||||||
|
if is_unsafe and data.highway == 'secondary' and not data.is_twoway then
|
||||||
|
safety_penalty = safety_penalty * 0.6
|
||||||
|
end
|
||||||
|
|
||||||
|
local forward_is_unsafe = is_unsafe and not data.has_cycleway_forward
|
||||||
|
local backward_is_unsafe = is_unsafe and not data.has_cycleway_backward
|
||||||
|
local is_undesireable = data.highway == "service" and profile.service_penalties[data.service]
|
||||||
|
local forward_penalty = 1.
|
||||||
|
local backward_penalty = 1.
|
||||||
|
if forward_is_unsafe then
|
||||||
|
forward_penalty = math.min(forward_penalty, safety_penalty)
|
||||||
|
end
|
||||||
|
if backward_is_unsafe then
|
||||||
|
backward_penalty = math.min(backward_penalty, safety_penalty)
|
||||||
|
end
|
||||||
|
|
||||||
|
if is_undesireable then
|
||||||
|
forward_penalty = math.min(forward_penalty, profile.service_penalties[data.service])
|
||||||
|
backward_penalty = math.min(backward_penalty, profile.service_penalties[data.service])
|
||||||
|
end
|
||||||
|
|
||||||
|
if result.forward_speed > 0 then
|
||||||
|
-- convert from km/h to m/s
|
||||||
|
result.forward_rate = result.forward_speed / 3.6 * forward_penalty
|
||||||
|
end
|
||||||
|
if result.backward_speed > 0 then
|
||||||
|
-- convert from km/h to m/s
|
||||||
|
result.backward_rate = result.backward_speed / 3.6 * backward_penalty
|
||||||
|
end
|
||||||
|
if result.duration > 0 then
|
||||||
|
result.weight = result.duration / forward_penalty
|
||||||
|
end
|
||||||
|
|
||||||
|
if data.highway == "bicycle" then
|
||||||
|
safety_bonus = safety_bonus + 0.2
|
||||||
if result.forward_speed > 0 then
|
if result.forward_speed > 0 then
|
||||||
-- convert from km/h to m/s
|
-- convert from km/h to m/s
|
||||||
result.forward_rate = result.forward_speed / 3.6 * forward_penalty
|
result.forward_rate = result.forward_speed / 3.6 * safety_bonus
|
||||||
end
|
end
|
||||||
if result.backward_speed > 0 then
|
if result.backward_speed > 0 then
|
||||||
-- convert from km/h to m/s
|
-- convert from km/h to m/s
|
||||||
result.backward_rate = result.backward_speed / 3.6 * backward_penalty
|
result.backward_rate = result.backward_speed / 3.6 * safety_bonus
|
||||||
end
|
end
|
||||||
if result.duration > 0 then
|
if result.duration > 0 then
|
||||||
result.weight = result.duration / forward_penalty
|
result.weight = result.duration / safety_bonus
|
||||||
end
|
end
|
||||||
|
end
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
function process_way(profile, way, result)
|
function process_way(profile, way, result)
|
||||||
-- the initial filtering of ways based on presence of tags
|
-- the initial filtering of ways based on presence of tags
|
||||||
-- affects processing times significantly, because all ways
|
-- affects processing times significantly, because all ways
|
||||||
@@ -542,6 +587,39 @@ function process_way(profile, way, result)
|
|||||||
local data = {
|
local data = {
|
||||||
-- prefetch tags
|
-- prefetch tags
|
||||||
highway = way:get_value_by_key('highway'),
|
highway = way:get_value_by_key('highway'),
|
||||||
|
|
||||||
|
route = nil,
|
||||||
|
man_made = nil,
|
||||||
|
railway = nil,
|
||||||
|
amenity = nil,
|
||||||
|
public_transport = nil,
|
||||||
|
bridge = nil,
|
||||||
|
|
||||||
|
access = nil,
|
||||||
|
|
||||||
|
junction = nil,
|
||||||
|
maxspeed = nil,
|
||||||
|
maxspeed_forward = nil,
|
||||||
|
maxspeed_backward = nil,
|
||||||
|
barrier = nil,
|
||||||
|
oneway = nil,
|
||||||
|
oneway_bicycle = nil,
|
||||||
|
cycleway = nil,
|
||||||
|
cycleway_left = nil,
|
||||||
|
cycleway_right = nil,
|
||||||
|
duration = nil,
|
||||||
|
service = nil,
|
||||||
|
foot = nil,
|
||||||
|
foot_forward = nil,
|
||||||
|
foot_backward = nil,
|
||||||
|
bicycle = nil,
|
||||||
|
|
||||||
|
way_type_allows_pushing = false,
|
||||||
|
has_cycleway_forward = false,
|
||||||
|
has_cycleway_backward = false,
|
||||||
|
is_twoway = true,
|
||||||
|
reverse = false,
|
||||||
|
implied_oneway = false
|
||||||
}
|
}
|
||||||
|
|
||||||
local handlers = Sequence {
|
local handlers = Sequence {
|
||||||
@@ -572,6 +650,9 @@ function process_way(profile, way, result)
|
|||||||
-- set name, ref and pronunciation
|
-- set name, ref and pronunciation
|
||||||
WayHandlers.names,
|
WayHandlers.names,
|
||||||
|
|
||||||
|
-- set classes
|
||||||
|
WayHandlers.classes,
|
||||||
|
|
||||||
-- set weight properties of the way
|
-- set weight properties of the way
|
||||||
WayHandlers.weights
|
WayHandlers.weights
|
||||||
}
|
}
|
||||||
|
|||||||
+7
-3
@@ -42,6 +42,10 @@ function setup()
|
|||||||
vehicle_height = 2.5, -- in meters, 2.5m is the height of van
|
vehicle_height = 2.5, -- in meters, 2.5m is the height of van
|
||||||
vehicle_width = 1.9, -- in meters, ways with narrow tag are considered narrower than 2.2m
|
vehicle_width = 1.9, -- in meters, ways with narrow tag are considered narrower than 2.2m
|
||||||
|
|
||||||
|
-- Size of the vehicle, to be limited mostly by legal restriction of the way
|
||||||
|
vehicle_length = 4.8, -- in meters, 4.8m is the length of large or familly car
|
||||||
|
vehicle_weight = 3500, -- in kilograms
|
||||||
|
|
||||||
-- a list of suffixes to suppress in name change instructions. The suffixes also include common substrings of each other
|
-- a list of suffixes to suppress in name change instructions. The suffixes also include common substrings of each other
|
||||||
suffix_list = {
|
suffix_list = {
|
||||||
'N', 'NE', 'E', 'SE', 'S', 'SW', 'W', 'NW', 'North', 'South', 'West', 'East', 'Nor', 'Sou', 'We', 'Ea'
|
'N', 'NE', 'E', 'SE', 'S', 'SW', 'W', 'NW', 'North', 'South', 'West', 'East', 'Nor', 'Sou', 'We', 'Ea'
|
||||||
@@ -116,9 +120,6 @@ function setup()
|
|||||||
|
|
||||||
-- classes to support for exclude flags
|
-- classes to support for exclude flags
|
||||||
excludable = Sequence {
|
excludable = Sequence {
|
||||||
Set {'toll'},
|
|
||||||
Set {'motorway'},
|
|
||||||
Set {'ferry'}
|
|
||||||
},
|
},
|
||||||
|
|
||||||
avoid = Set {
|
avoid = Set {
|
||||||
@@ -276,6 +277,7 @@ function setup()
|
|||||||
["de:rural"] = 100,
|
["de:rural"] = 100,
|
||||||
["de:motorway"] = 0,
|
["de:motorway"] = 0,
|
||||||
["dk:rural"] = 80,
|
["dk:rural"] = 80,
|
||||||
|
["fr:rural"] = 80,
|
||||||
["gb:nsl_single"] = (60*1609)/1000,
|
["gb:nsl_single"] = (60*1609)/1000,
|
||||||
["gb:nsl_dual"] = (70*1609)/1000,
|
["gb:nsl_dual"] = (70*1609)/1000,
|
||||||
["gb:motorway"] = (70*1609)/1000,
|
["gb:motorway"] = (70*1609)/1000,
|
||||||
@@ -387,6 +389,8 @@ function process_way(profile, way, result, relations)
|
|||||||
WayHandlers.avoid_ways,
|
WayHandlers.avoid_ways,
|
||||||
WayHandlers.handle_height,
|
WayHandlers.handle_height,
|
||||||
WayHandlers.handle_width,
|
WayHandlers.handle_width,
|
||||||
|
WayHandlers.handle_length,
|
||||||
|
WayHandlers.handle_weight,
|
||||||
|
|
||||||
-- determine access status by checking our hierarchy of
|
-- determine access status by checking our hierarchy of
|
||||||
-- access tags, e.g: motorcar, motor_vehicle, vehicle
|
-- access tags, e.g: motorcar, motor_vehicle, vehicle
|
||||||
|
|||||||
+5
-14
@@ -24,19 +24,10 @@ function setup()
|
|||||||
default_speed = walking_speed,
|
default_speed = walking_speed,
|
||||||
oneway_handling = 'specific', -- respect 'oneway:foot' but not 'oneway'
|
oneway_handling = 'specific', -- respect 'oneway:foot' but not 'oneway'
|
||||||
|
|
||||||
barrier_whitelist = Set {
|
barrier_blacklist = Set {
|
||||||
'cycle_barrier',
|
'yes',
|
||||||
'bollard',
|
'wall',
|
||||||
'entrance',
|
'fence'
|
||||||
'cattle_grid',
|
|
||||||
'border_control',
|
|
||||||
'toll_booth',
|
|
||||||
'sally_port',
|
|
||||||
'gate',
|
|
||||||
'lift_gate',
|
|
||||||
'no',
|
|
||||||
'kerb',
|
|
||||||
'block'
|
|
||||||
},
|
},
|
||||||
|
|
||||||
access_tag_whitelist = Set {
|
access_tag_whitelist = Set {
|
||||||
@@ -157,7 +148,7 @@ function process_node(profile, node, result)
|
|||||||
local bollard = node:get_value_by_key("bollard")
|
local bollard = node:get_value_by_key("bollard")
|
||||||
local rising_bollard = bollard and "rising" == bollard
|
local rising_bollard = bollard and "rising" == bollard
|
||||||
|
|
||||||
if not profile.barrier_whitelist[barrier] and not rising_bollard then
|
if profile.barrier_blacklist[barrier] and not rising_bollard then
|
||||||
result.barrier = true
|
result.barrier = true
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|||||||
+20
-26
@@ -5,6 +5,7 @@ Measure = {}
|
|||||||
-- measurements conversion constants
|
-- measurements conversion constants
|
||||||
local inch_to_meters = 0.0254
|
local inch_to_meters = 0.0254
|
||||||
local feet_to_inches = 12
|
local feet_to_inches = 12
|
||||||
|
local pound_to_kilograms = 0.45359237
|
||||||
|
|
||||||
--- Parse string as a height in meters.
|
--- Parse string as a height in meters.
|
||||||
--- according to http://wiki.openstreetmap.org/wiki/Key:maxheight
|
--- according to http://wiki.openstreetmap.org/wiki/Key:maxheight
|
||||||
@@ -25,33 +26,19 @@ function Measure.parse_value_meters(value)
|
|||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
--- according to http://wiki.openstreetmap.org/wiki/Map_Features/Units#Explicit_specifications
|
--- Parse weight value in kilograms.
|
||||||
local tonns_parse_patterns = Sequence {
|
--- according to https://wiki.openstreetmap.org/wiki/Key:maxweight
|
||||||
"%d+",
|
|
||||||
"%d+.%d+",
|
|
||||||
"%d+.%d+ ?t"
|
|
||||||
}
|
|
||||||
|
|
||||||
local kg_parse_patterns = Sequence {
|
|
||||||
"%d+ ?kg"
|
|
||||||
}
|
|
||||||
|
|
||||||
--- Parse weight value in kilograms
|
|
||||||
function Measure.parse_value_kilograms(value)
|
function Measure.parse_value_kilograms(value)
|
||||||
-- try to parse kilograms
|
local n = tonumber(value:gsub(",", "."):match("%d+%.?%d*"))
|
||||||
for i, templ in ipairs(kg_parse_patterns) do
|
if n then
|
||||||
m = string.match(value, templ)
|
if string.match(value, "lbs") then
|
||||||
if m then
|
n = n * pound_to_kilograms
|
||||||
return tonumber(m)
|
elseif string.match(value, "kg") then
|
||||||
end
|
-- n = n
|
||||||
end
|
else -- Default, metric tons
|
||||||
|
n = n * 1000
|
||||||
-- try to parse tonns
|
|
||||||
for i, templ in ipairs(tonns_parse_patterns) do
|
|
||||||
m = string.match(value, templ)
|
|
||||||
if m then
|
|
||||||
return tonumber(m) * 1000
|
|
||||||
end
|
end
|
||||||
|
return n
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
@@ -83,7 +70,14 @@ function Measure.get_max_width(raw_value)
|
|||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
--- Get maxweight of specified way in kilogramms
|
--- Get maxlength of specified way in meters.
|
||||||
|
function Measure.get_max_length(raw_value)
|
||||||
|
if raw_value then
|
||||||
|
return Measure.parse_value_meters(raw_value)
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
--- Get maxweight of specified way in kilogramms.
|
||||||
function Measure.get_max_weight(raw_value)
|
function Measure.get_max_weight(raw_value)
|
||||||
if raw_value then
|
if raw_value then
|
||||||
return Measure.parse_value_kilograms(raw_value)
|
return Measure.parse_value_kilograms(raw_value)
|
||||||
|
|||||||
@@ -306,37 +306,46 @@ end
|
|||||||
|
|
||||||
-- add class information
|
-- add class information
|
||||||
function WayHandlers.classes(profile,way,result,data)
|
function WayHandlers.classes(profile,way,result,data)
|
||||||
|
if not profile.classes then
|
||||||
|
return
|
||||||
|
end
|
||||||
|
|
||||||
|
local allowed_classes = Set {}
|
||||||
|
for k, v in pairs(profile.classes) do
|
||||||
|
allowed_classes[v] = true
|
||||||
|
end
|
||||||
|
|
||||||
local forward_toll, backward_toll = Tags.get_forward_backward_by_key(way, data, "toll")
|
local forward_toll, backward_toll = Tags.get_forward_backward_by_key(way, data, "toll")
|
||||||
local forward_route, backward_route = Tags.get_forward_backward_by_key(way, data, "route")
|
local forward_route, backward_route = Tags.get_forward_backward_by_key(way, data, "route")
|
||||||
local tunnel = way:get_value_by_key("tunnel")
|
local tunnel = way:get_value_by_key("tunnel")
|
||||||
|
|
||||||
if tunnel and tunnel ~= "no" then
|
if allowed_classes["tunnel"] and tunnel and tunnel ~= "no" then
|
||||||
result.forward_classes["tunnel"] = true
|
result.forward_classes["tunnel"] = true
|
||||||
result.backward_classes["tunnel"] = true
|
result.backward_classes["tunnel"] = true
|
||||||
end
|
end
|
||||||
|
|
||||||
if forward_toll == "yes" then
|
if allowed_classes["toll"] and forward_toll == "yes" then
|
||||||
result.forward_classes["toll"] = true
|
result.forward_classes["toll"] = true
|
||||||
end
|
end
|
||||||
if backward_toll == "yes" then
|
if allowed_classes["toll"] and backward_toll == "yes" then
|
||||||
result.backward_classes["toll"] = true
|
result.backward_classes["toll"] = true
|
||||||
end
|
end
|
||||||
|
|
||||||
if forward_route == "ferry" then
|
if allowed_classes["ferry"] and forward_route == "ferry" then
|
||||||
result.forward_classes["ferry"] = true
|
result.forward_classes["ferry"] = true
|
||||||
end
|
end
|
||||||
if backward_route == "ferry" then
|
if allowed_classes["ferry"] and backward_route == "ferry" then
|
||||||
result.backward_classes["ferry"] = true
|
result.backward_classes["ferry"] = true
|
||||||
end
|
end
|
||||||
|
|
||||||
if result.forward_restricted then
|
if allowed_classes["restricted"] and result.forward_restricted then
|
||||||
result.forward_classes["restricted"] = true
|
result.forward_classes["restricted"] = true
|
||||||
end
|
end
|
||||||
if result.backward_restricted then
|
if allowed_classes["restricted"] and result.backward_restricted then
|
||||||
result.backward_classes["restricted"] = true
|
result.backward_classes["restricted"] = true
|
||||||
end
|
end
|
||||||
|
|
||||||
if data.highway == "motorway" or data.highway == "motorway_link" then
|
if allowed_classes["motorway"] and (data.highway == "motorway" or data.highway == "motorway_link") then
|
||||||
result.forward_classes["motorway"] = true
|
result.forward_classes["motorway"] = true
|
||||||
result.backward_classes["motorway"] = true
|
result.backward_classes["motorway"] = true
|
||||||
end
|
end
|
||||||
@@ -502,6 +511,38 @@ function WayHandlers.handle_width(profile,way,result,data)
|
|||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
|
-- handle maxweight tags
|
||||||
|
function WayHandlers.handle_weight(profile,way,result,data)
|
||||||
|
local keys = Sequence { 'maxweight' }
|
||||||
|
local forward, backward = Tags.get_forward_backward_by_set(way,data,keys)
|
||||||
|
forward = Measure.get_max_weight(forward)
|
||||||
|
backward = Measure.get_max_weight(backward)
|
||||||
|
|
||||||
|
if forward and forward < profile.vehicle_weight then
|
||||||
|
result.forward_mode = mode.inaccessible
|
||||||
|
end
|
||||||
|
|
||||||
|
if backward and backward < profile.vehicle_weight then
|
||||||
|
result.backward_mode = mode.inaccessible
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
-- handle maxlength tags
|
||||||
|
function WayHandlers.handle_length(profile,way,result,data)
|
||||||
|
local keys = Sequence { 'maxlength' }
|
||||||
|
local forward, backward = Tags.get_forward_backward_by_set(way,data,keys)
|
||||||
|
forward = Measure.get_max_length(forward)
|
||||||
|
backward = Measure.get_max_length(backward)
|
||||||
|
|
||||||
|
if forward and forward < profile.vehicle_length then
|
||||||
|
result.forward_mode = mode.inaccessible
|
||||||
|
end
|
||||||
|
|
||||||
|
if backward and backward < profile.vehicle_length then
|
||||||
|
result.backward_mode = mode.inaccessible
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
-- handle oneways tags
|
-- handle oneways tags
|
||||||
function WayHandlers.oneway(profile,way,result,data)
|
function WayHandlers.oneway(profile,way,result,data)
|
||||||
if not profile.oneway_handling then
|
if not profile.oneway_handling then
|
||||||
|
|||||||
@@ -5,7 +5,7 @@
|
|||||||
-- Secondary road: 18km/h = 18000m/3600s = 100m/20s
|
-- Secondary road: 18km/h = 18000m/3600s = 100m/20s
|
||||||
-- Tertiary road: 12km/h = 12000m/3600s = 100m/30s
|
-- Tertiary road: 12km/h = 12000m/3600s = 100m/30s
|
||||||
|
|
||||||
api_version = 3
|
api_version = 4
|
||||||
|
|
||||||
function setup()
|
function setup()
|
||||||
return {
|
return {
|
||||||
@@ -14,7 +14,7 @@ function setup()
|
|||||||
max_speed_for_map_matching = 30/3.6, --km -> m/s
|
max_speed_for_map_matching = 30/3.6, --km -> m/s
|
||||||
weight_name = 'duration',
|
weight_name = 'duration',
|
||||||
process_call_tagless_node = false,
|
process_call_tagless_node = false,
|
||||||
uturn_penalty = 20,
|
u_turn_penalty = 20,
|
||||||
traffic_light_penalty = 7, -- seconds
|
traffic_light_penalty = 7, -- seconds
|
||||||
use_turn_restrictions = true
|
use_turn_restrictions = true
|
||||||
},
|
},
|
||||||
@@ -32,7 +32,7 @@ function setup()
|
|||||||
primary = 36,
|
primary = 36,
|
||||||
secondary = 18,
|
secondary = 18,
|
||||||
tertiary = 12,
|
tertiary = 12,
|
||||||
steps = 6,
|
steps = 6
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
end
|
end
|
||||||
@@ -128,9 +128,9 @@ function process_way (profile, way, result)
|
|||||||
end
|
end
|
||||||
|
|
||||||
function process_turn (profile, turn)
|
function process_turn (profile, turn)
|
||||||
if turn.direction_modifier == direction_modifier.uturn then
|
if turn.is_u_turn then
|
||||||
turn.duration = profile.properties.uturn_penalty
|
turn.duration = turn.duration + profile.properties.u_turn_penalty
|
||||||
turn.weight = profile.properties.uturn_penalty
|
turn.weight = turn.weight + profile.properties.u_turn_penalty
|
||||||
end
|
end
|
||||||
if turn.has_traffic_light then
|
if turn.has_traffic_light then
|
||||||
turn.duration = turn.duration + profile.properties.traffic_light_penalty
|
turn.duration = turn.duration + profile.properties.traffic_light_penalty
|
||||||
|
|||||||
@@ -9,6 +9,8 @@ lonlat = lambda x: (coord2float(x['lon']['__value']), coord2float(x['lat']['__va
|
|||||||
|
|
||||||
def call(this, method, *args):
|
def call(this, method, *args):
|
||||||
"""Call this.method(args)"""
|
"""Call this.method(args)"""
|
||||||
|
if (str(this) == '<optimized out>'):
|
||||||
|
raise BaseException('"this" is optimized out')
|
||||||
command = '(*({})({})).{}({})'.format(this.type.target().pointer(), this.address, method, ','.join((str(x) for x in args)))
|
command = '(*({})({})).{}({})'.format(this.type.target().pointer(), this.address, method, ','.join((str(x) for x in args)))
|
||||||
return gdb.parse_and_eval(command)
|
return gdb.parse_and_eval(command)
|
||||||
|
|
||||||
@@ -234,7 +236,6 @@ class SVGPrinter (gdb.Command):
|
|||||||
mld_facade = facade.cast(gdb.lookup_type('osrm::engine::datafacade::ContiguousInternalMemoryAlgorithmDataFacade<osrm::engine::routing_algorithms::mld::Algorithm>'))
|
mld_facade = facade.cast(gdb.lookup_type('osrm::engine::datafacade::ContiguousInternalMemoryAlgorithmDataFacade<osrm::engine::routing_algorithms::mld::Algorithm>'))
|
||||||
mld_partition = mld_facade['mld_partition']
|
mld_partition = mld_facade['mld_partition']
|
||||||
mld_levels = call(mld_partition, 'GetNumberOfLevels')
|
mld_levels = call(mld_partition, 'GetNumberOfLevels')
|
||||||
print (mld_level, mld_levels)
|
|
||||||
if mld_level < mld_levels:
|
if mld_level < mld_levels:
|
||||||
sentinel_node = call(mld_partition['partition'], 'size') - 1 # GetSentinelNode
|
sentinel_node = call(mld_partition['partition'], 'size') - 1 # GetSentinelNode
|
||||||
number_of_cells = call(mld_partition, 'GetCell', mld_level, sentinel_node) # GetNumberOfCells
|
number_of_cells = call(mld_partition, 'GetCell', mld_level, sentinel_node) # GetNumberOfCells
|
||||||
@@ -272,6 +273,7 @@ class SVGPrinter (gdb.Command):
|
|||||||
for node in nodes:
|
for node in nodes:
|
||||||
geometry_id = call(facade, 'GetGeometryIndex', node)
|
geometry_id = call(facade, 'GetGeometryIndex', node)
|
||||||
direction = 'forward' if geometry_id['forward'] else 'reverse'
|
direction = 'forward' if geometry_id['forward'] else 'reverse'
|
||||||
|
print (geometry_id, direction)
|
||||||
geometry = SVGPrinter.getByGeometryId(facade, geometry_id, 'Geometry')
|
geometry = SVGPrinter.getByGeometryId(facade, geometry_id, 'Geometry')
|
||||||
weights = SVGPrinter.getByGeometryId(facade, geometry_id, 'Weights')
|
weights = SVGPrinter.getByGeometryId(facade, geometry_id, 'Weights')
|
||||||
|
|
||||||
|
|||||||
@@ -0,0 +1,43 @@
|
|||||||
|
/*********************************
|
||||||
|
* Takes an XML `.osm` file and converts it into a cucumber scenario definition like
|
||||||
|
* Given the node locations
|
||||||
|
* | node | lon | lat |
|
||||||
|
* .....
|
||||||
|
* Given the ways
|
||||||
|
* | nodes | tag1 | tag2 | tag3 |
|
||||||
|
* .....
|
||||||
|
*
|
||||||
|
* Note that cucumber tests are limited to 26 nodes (labelled a-z), so
|
||||||
|
* you'll need to use pretty small OSM extracts to get this to work.
|
||||||
|
*****************************************/
|
||||||
|
var fs = require('fs');
|
||||||
|
var parseString = require('xml2js').parseString;
|
||||||
|
|
||||||
|
var data = fs.readFileSync('filename.osm', 'utf8');
|
||||||
|
|
||||||
|
const items = parseString(data, (err, result) => {
|
||||||
|
var idmap = {};
|
||||||
|
|
||||||
|
console.log('Given the node locations');
|
||||||
|
console.log(' | node | lon | lat |');
|
||||||
|
result.osm.node.filter(n => !n.$.action || n.$.action !== 'delete').forEach(i => {
|
||||||
|
var code = String.fromCharCode(97 + Object.keys(idmap).length)
|
||||||
|
idmap[i.$.id] = code;
|
||||||
|
console.log(` | ${code} | ${i.$.lon} | ${i.$.lat} |`);
|
||||||
|
});
|
||||||
|
|
||||||
|
var allkeys = {};
|
||||||
|
var waytags = {};
|
||||||
|
|
||||||
|
result.osm.way.filter(n => !n.$.action || n.$.action !== 'delete').forEach(w => {
|
||||||
|
if (!waytags[w.$.id]) waytags[w.$.id] = {};
|
||||||
|
w.tag.forEach(t => { allkeys[t.$.k] = t.$.v; waytags[w.$.id][t.$.k] = t.$.v; });
|
||||||
|
});
|
||||||
|
|
||||||
|
console.log('And the ways');
|
||||||
|
console.log(` | nodes | ${Object.keys(allkeys).join(' | ')} |`);
|
||||||
|
|
||||||
|
result.osm.way.filter(n => !n.$.action || n.$.action !== 'delete').forEach(w => {
|
||||||
|
console.log(` | ${w.nd.map(n => idmap[n.$.ref]).join('')} | ${Object.keys(allkeys).map(k => waytags[w.$.id][k] || '').join(' | ')} |`);
|
||||||
|
});
|
||||||
|
});
|
||||||
+60
-45
@@ -10,13 +10,12 @@ const clu = require('command-line-usage');
|
|||||||
const ansi = require('ansi-escape-sequences');
|
const ansi = require('ansi-escape-sequences');
|
||||||
const turf = require('turf');
|
const turf = require('turf');
|
||||||
const jp = require('jsonpath');
|
const jp = require('jsonpath');
|
||||||
|
const csv_stringify = require('csv-stringify/lib/sync');
|
||||||
|
|
||||||
const run_query = (query_options, filters, callback) => {
|
const run_query = (query_options, filters, callback) => {
|
||||||
let tic = () => 0.;
|
let tic = () => 0.;
|
||||||
http.request(query_options, function (res) {
|
http.request(query_options, function (res) {
|
||||||
let body = '', ttfb = tic();
|
let body = '', ttfb = tic();
|
||||||
if (res.statusCode != 200)
|
|
||||||
return callback(query_options.path, res.statusCode, ttfb);
|
|
||||||
|
|
||||||
res.setEncoding('utf8');
|
res.setEncoding('utf8');
|
||||||
res.on('data', function (chunk) {
|
res.on('data', function (chunk) {
|
||||||
@@ -35,27 +34,51 @@ const run_query = (query_options, filters, callback) => {
|
|||||||
}).end();
|
}).end();
|
||||||
};
|
};
|
||||||
|
|
||||||
function generate_points(polygon, number) {
|
function generate_points(polygon, number, coordinates_number, max_distance) {
|
||||||
let query_points = [];
|
let query_points = [];
|
||||||
while (query_points.length < number) {
|
while (query_points.length < number) {
|
||||||
var chunk = turf
|
let points = [];
|
||||||
.random('points', number, { bbox: turf.bbox(polygon)})
|
|
||||||
.features
|
while(points.length < coordinates_number) {
|
||||||
.map(x => x.geometry.coordinates)
|
let chunk = turf
|
||||||
.filter(pt => turf.inside(pt, polygon));
|
.random('points', coordinates_number, { bbox: turf.bbox(polygon)})
|
||||||
query_points = query_points.concat(chunk);
|
.features
|
||||||
|
.map(x => x.geometry.coordinates)
|
||||||
|
.filter(pt => turf.inside(pt, polygon));
|
||||||
|
|
||||||
|
if (max_distance > 0)
|
||||||
|
{
|
||||||
|
chunk.forEach(pt => {
|
||||||
|
if (points.length == 0)
|
||||||
|
{
|
||||||
|
points.push(pt);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
let distance = turf.distance(pt, points[points.length-1], 'meters');
|
||||||
|
if (distance < max_distance)
|
||||||
|
{
|
||||||
|
points.push(pt);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
});
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
points = points.concat(chunk);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
query_points.push(points);
|
||||||
}
|
}
|
||||||
return query_points.slice(0, number);
|
|
||||||
|
return query_points;
|
||||||
}
|
}
|
||||||
|
|
||||||
function generate_queries(options, query_points, coordinates_number) {
|
function generate_queries(options, query_points) {
|
||||||
let queries = [];
|
let queries = query_points.map(points => {
|
||||||
for (let chunk = 0; chunk < query_points.length; chunk += coordinates_number)
|
return options.path.replace(/{}/g, x => points.pop().join(','));
|
||||||
{
|
});
|
||||||
let points = query_points.slice(chunk, chunk + coordinates_number);
|
|
||||||
let query = options.path.replace(/{}/g, x => points.pop().join(','));
|
|
||||||
queries.push(query);
|
|
||||||
}
|
|
||||||
return queries;
|
return queries;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -73,27 +96,22 @@ function BoundingBox(x) {
|
|||||||
}
|
}
|
||||||
const optionsList = [
|
const optionsList = [
|
||||||
{name: 'help', alias: 'h', type: Boolean, description: 'Display this usage guide.', defaultValue: false},
|
{name: 'help', alias: 'h', type: Boolean, description: 'Display this usage guide.', defaultValue: false},
|
||||||
{name: 'server', alias: 's', type: ServerDetails, defaultValue: ServerDetails('localhost:5000'),
|
{name: 'server', alias: 's', type: ServerDetails, defaultValue: ServerDetails('localhost:5000'), description: 'OSRM routing server', typeLabel: '{underline hostname[:port]}'},
|
||||||
description: 'OSRM routing server', typeLabel: '[underline]{hostname[:port]}'},
|
{name: 'path', alias: 'p', type: String, defaultValue: '/route/v1/driving/{};{}', description: 'OSRM query path with \\{\\} coordinate placeholders, default /route/v2/driving/\\{\\};\\{\\}', typeLabel: '{underline path}'},
|
||||||
{name: 'path', alias: 'p', type: String, defaultValue: '/route/v1/driving/{};{}',
|
{name: 'filter', alias: 'f', type: String, defaultValue: ['$.routes[0].weight'], multiple: true, description: 'JSONPath filters, default "$.routes[0].weight"', typeLabel: '{underline filter}'},
|
||||||
description: 'OSRM query path with {} coordinate placeholders, default /route/v1/driving/{};{}', typeLabel: '[underline]{path}'},
|
{name: 'bounding-box', alias: 'b', type: BoundingBox, defaultValue: BoundingBox('5.86442,47.2654,15.0508,55.1478'), multiple: true, description: 'queries bounding box, default "5.86442,47.2654,15.0508,55.1478"', typeLabel: '{underline west,south,east,north}'},
|
||||||
{name: 'filter', alias: 'f', type: String, defaultValue: ['$.routes[0].weight'], multiple: true,
|
{name: 'max-sockets', alias: 'm', type: Number, defaultValue: 1, description: 'how many concurrent sockets the agent can have open per origin, default 1', typeLabel: '{underline number}'},
|
||||||
description: 'JSONPath filters, default "$.routes[0].weight"', typeLabel: '[underline]{filter}'},
|
{name: 'number', alias: 'n', type: Number, defaultValue: 10, description: 'number of query points, default 10', typeLabel: '{underline number}'},
|
||||||
{name: 'bounding-box', alias: 'b', type: BoundingBox, defaultValue: BoundingBox('5.86442,47.2654,15.0508,55.1478'), multiple: true,
|
{name: 'max-distance', alias: 'd', type: Number, defaultValue: -1, description: 'maximal distance between coordinates', typeLabel: '{underline number}'},
|
||||||
description: 'queries bounding box, default "5.86442,47.2654,15.0508,55.1478"', typeLabel: '[underline]{west,south,east,north}'},
|
{name: 'queries-files', alias: 'q', type: String, description: 'CSV file with queries in the first row', typeLabel: '{underline file}'},
|
||||||
{name: 'max-sockets', alias: 'm', type: Number, defaultValue: 1,
|
];
|
||||||
description: 'how many concurrent sockets the agent can have open per origin, default 1', typeLabel: '[underline]{number}'},
|
|
||||||
{name: 'number', alias: 'n', type: Number, defaultValue: 10,
|
|
||||||
description: 'number of query points, default 10', typeLabel: '[underline]{number}'},
|
|
||||||
{name: 'queries-files', alias: 'q', type: String,
|
|
||||||
description: 'CSV file with queries in the first row', typeLabel: '[underline]{file}'}];
|
|
||||||
const options = cla(optionsList);
|
const options = cla(optionsList);
|
||||||
if (options.help) {
|
if (options.help) {
|
||||||
const banner =
|
const banner =`\
|
||||||
String.raw` ____ _______ __ ___ ___ __ ___ ___ _________ ` + '\n' +
|
____ _______ __ ______ __ ___ ___ _________
|
||||||
String.raw` / __ \/ __/ _ \/ |/ / / _ \/ / / / |/ / |/ / __/ _ \ ` + '\n' +
|
/ __ \\\\/ __/ _ \\\\/ |/ / _ \\\\/ / / / |/ / |/ / __/ _ \\\\
|
||||||
String.raw`/ /_/ /\ \/ , _/ /|_/ / / , _/ /_/ / / / _// , _/ ` + '\n' +
|
/ /_/ /\\\\ \\\\/ , _/ /|_/ / , _/ /_/ / / / _// , _/
|
||||||
String.raw`\____/___/_/|_/_/ /_/ /_/|_|\____/_/|_/_/|_/___/_/|_| `;
|
\\\\____/___/_/|_/_/ /_/_/|_|\\\\____/_/|_/_/|_/___/_/|_|`;
|
||||||
const usage = clu([
|
const usage = clu([
|
||||||
{ content: ansi.format(banner, 'green'), raw: true },
|
{ content: ansi.format(banner, 'green'), raw: true },
|
||||||
{ header: 'Run OSRM queries and collect results'/*, content: 'Generates something [italic]{very} important.'*/ },
|
{ header: 'Run OSRM queries and collect results'/*, content: 'Generates something [italic]{very} important.'*/ },
|
||||||
@@ -114,8 +132,8 @@ if (options.hasOwnProperty('queries-files')) {
|
|||||||
} else {
|
} else {
|
||||||
const polygon = options['bounding-box'].map(x => x.poly).reduce((x,y) => turf.union(x, y));
|
const polygon = options['bounding-box'].map(x => x.poly).reduce((x,y) => turf.union(x, y));
|
||||||
const coordinates_number = (options.path.match(/{}/g) || []).length;
|
const coordinates_number = (options.path.match(/{}/g) || []).length;
|
||||||
const query_points = generate_points(polygon, coordinates_number * options.number);
|
const query_points = generate_points(polygon, options.number, coordinates_number, options['max-distance']);
|
||||||
queries = generate_queries(options, query_points, coordinates_number);
|
queries = generate_queries(options, query_points);
|
||||||
}
|
}
|
||||||
queries = queries.map(q => { return {hostname: options.server.hostname, port: options.server.port, path: q}; });
|
queries = queries.map(q => { return {hostname: options.server.hostname, port: options.server.port, path: q}; });
|
||||||
|
|
||||||
@@ -123,11 +141,8 @@ queries = queries.map(q => { return {hostname: options.server.hostname, port: op
|
|||||||
http.globalAgent.maxSockets = options['max-sockets'];
|
http.globalAgent.maxSockets = options['max-sockets'];
|
||||||
queries.map(query => {
|
queries.map(query => {
|
||||||
run_query(query, options.filter, (query, code, ttfb, total, results) => {
|
run_query(query, options.filter, (query, code, ttfb, total, results) => {
|
||||||
let str = `"${query}",${code}`;
|
let data = results ? JSON.stringify(results[0]) : '';
|
||||||
if (ttfb !== undefined) str += `,${ttfb}`;
|
let record = [[query, code, ttfb, total, data]];
|
||||||
if (total !== undefined) str += `,${total}`;
|
process.stdout.write(csv_stringify(record));
|
||||||
if (typeof results === 'object' && results.length > 0)
|
|
||||||
str += ',' + results.map(x => isNaN(x) ? '"' + JSON.stringify(x).replace(/\n/g, ';').replace(/"/g, "'") + '"' : Number(x)).join(',');
|
|
||||||
console.log(str);
|
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
|||||||
@@ -9,79 +9,50 @@ set -o nounset
|
|||||||
# structure will be lost.
|
# structure will be lost.
|
||||||
# http://git.661346.n2.nabble.com/subtree-merges-lose-prefix-after-rebase-td7332850.html
|
# http://git.661346.n2.nabble.com/subtree-merges-lose-prefix-after-rebase-td7332850.html
|
||||||
|
|
||||||
OSMIUM_REPO="https://github.com/osmcode/libosmium.git"
|
OSMIUM_PATH="osmcode/libosmium"
|
||||||
OSMIUM_TAG=v2.13.1
|
OSMIUM_TAG=v2.14.0
|
||||||
|
|
||||||
VARIANT_REPO="https://github.com/mapbox/variant.git"
|
VARIANT_PATH="mapbox/variant"
|
||||||
VARIANT_TAG=v1.1.3
|
VARIANT_TAG=v1.1.3
|
||||||
|
|
||||||
SOL_REPO="https://github.com/ThePhD/sol2.git"
|
SOL_PATH="ThePhD/sol2"
|
||||||
SOL_TAG=v2.17.5
|
SOL_TAG=v2.17.5
|
||||||
|
|
||||||
RAPIDJSON_REPO="https://github.com/miloyip/rapidjson.git"
|
RAPIDJSON_PATH="Tencent/rapidjson"
|
||||||
RAPIDJSON_TAG=v1.1.0
|
RAPIDJSON_TAG=v1.1.0
|
||||||
|
|
||||||
MICROTAR_REPO="https://github.com/rxi/microtar"
|
MICROTAR_PATH="rxi/microtar"
|
||||||
MICROTAR_TAG=v0.1.0
|
MICROTAR_TAG=v0.1.0
|
||||||
|
|
||||||
VARIANT_LATEST=$(curl "https://api.github.com/repos/mapbox/variant/releases/latest" | jq ".tag_name")
|
PROTOZERO_PATH="mapbox/protozero"
|
||||||
OSMIUM_LATEST=$(curl "https://api.github.com/repos/osmcode/libosmium/releases/latest" | jq ".tag_name")
|
PROTOZERO_TAG=v1.6.2
|
||||||
SOL_LATEST=$(curl "https://api.github.com/repos/ThePhD/sol2/releases/latest" | jq ".tag_name")
|
|
||||||
RAPIDJSON_LATEST=$(curl "https://api.github.com/repos/miloyip/rapidjson/releases/latest" | jq ".tag_name")
|
|
||||||
MICROTAR_LATEST=$(curl "https://api.github.com/repos/rxi/microtar/releases/latest" | jq ".tag_name")
|
|
||||||
|
|
||||||
echo "Latest osmium release is $OSMIUM_LATEST, pulling in \"$OSMIUM_TAG\""
|
VTZERO_PATH="mapbox/vtzero"
|
||||||
echo "Latest variant release is $VARIANT_LATEST, pulling in \"$VARIANT_TAG\""
|
VTZERO_TAG=v1.0.1
|
||||||
echo "Latest sol2 release is $SOL_LATEST, pulling in \"$SOL_TAG\""
|
|
||||||
echo "Latest rapidjson release is $RAPIDJSON_LATEST, pulling in \"$RAPIDJSON_TAG\""
|
|
||||||
echo "Latest microtar release is $MICROTAR_LATEST, pulling in \"$MICROTAR_TAG\""
|
|
||||||
|
|
||||||
read -p "Update osmium (y/n) " ok
|
function update_subtree () {
|
||||||
if [[ $ok =~ [yY] ]]
|
name=${1^^}
|
||||||
then
|
path=$(tmpvar=${name}_PATH && echo ${!tmpvar})
|
||||||
if [ -d "third_party/libosmium" ]; then
|
tag=$(tmpvar=${name}_TAG && echo ${!tmpvar})
|
||||||
git subtree pull -P third_party/libosmium/ $OSMIUM_REPO $OSMIUM_TAG --squash
|
dir=$(basename $path)
|
||||||
else
|
repo="https://github.com/${path}.git"
|
||||||
git subtree add -P third_party/libosmium/ $OSMIUM_REPO $OSMIUM_TAG --squash
|
latest=$(curl -s "https://api.github.com/repos/${path}/releases/latest" | jq ".tag_name")
|
||||||
fi
|
|
||||||
fi
|
|
||||||
|
|
||||||
read -p "Update variant (y/n) " ok
|
echo "Latest $1 release is ${latest}, pulling in \"${tag}\""
|
||||||
if [[ $ok =~ [yY] ]]
|
|
||||||
then
|
|
||||||
if [ -d "third_party/variant" ]; then
|
|
||||||
git subtree pull -P third_party/variant/ $VARIANT_REPO $VARIANT_TAG --squash
|
|
||||||
else
|
|
||||||
git subtree add -P third_party/variant/ $VARIANT_REPO $VARIANT_TAG --squash
|
|
||||||
fi
|
|
||||||
fi
|
|
||||||
|
|
||||||
read -p "Update sol2 (y/n) " ok
|
read -p "Update ${1} (y/n) " ok
|
||||||
if [[ $ok =~ [yY] ]]
|
|
||||||
then
|
|
||||||
if [ -d "third_party/sol2" ]; then
|
|
||||||
git subtree pull -P third_party/sol2/sol2/ $SOL_REPO $SOL_TAG --squash
|
|
||||||
else
|
|
||||||
git subtree add -P third_party/sol2/sol2/ $SOL_REPO $SOL_TAG --squash
|
|
||||||
fi
|
|
||||||
fi
|
|
||||||
|
|
||||||
read -p "Update rapidjson (y/n) " ok
|
if [[ $ok =~ [yY] ]]
|
||||||
if [[ $ok =~ [yY] ]]
|
then
|
||||||
then
|
if [ -d "third_party/$dir" ]; then
|
||||||
if [ -d "third_party/rapidjson" ]; then
|
git subtree pull -P third_party/$dir ${repo} ${tag} --squash
|
||||||
git subtree pull -P third_party/rapidjson/ $RAPIDJSON_REPO $RAPIDJSON_TAG --squash
|
else
|
||||||
else
|
git subtree add -P third_party/$dir ${repo} ${tag} --squash
|
||||||
git subtree add -P third_party/rapidjson/ $RAPIDJSON_REPO $RAPIDJSON_TAG --squash
|
fi
|
||||||
fi
|
fi
|
||||||
fi
|
}
|
||||||
|
|
||||||
read -p "Update microtar (y/n) " ok
|
## Update dependencies
|
||||||
if [[ $ok =~ [yY] ]]
|
for dep in osmium variant sol rapidjson microtar protozero vtzero ; do
|
||||||
then
|
update_subtree $dep
|
||||||
if [ -d "third_party/microtar" ]; then
|
done
|
||||||
git subtree pull -P third_party/microtar/ $MICROTAR_REPO $MICROTAR_TAG --squash
|
|
||||||
else
|
|
||||||
git subtree add -P third_party/microtar/ $MICROTAR_REPO $MICROTAR_TAG --squash
|
|
||||||
fi
|
|
||||||
fi
|
|
||||||
|
|||||||
@@ -75,6 +75,12 @@ int Contractor::Run()
|
|||||||
EdgeID number_of_edge_based_nodes = updater.LoadAndUpdateEdgeExpandedGraph(
|
EdgeID number_of_edge_based_nodes = updater.LoadAndUpdateEdgeExpandedGraph(
|
||||||
edge_based_edge_list, node_weights, connectivity_checksum);
|
edge_based_edge_list, node_weights, connectivity_checksum);
|
||||||
|
|
||||||
|
// Convert node weights for oneway streets to INVALID_EDGE_WEIGHT
|
||||||
|
for (auto &weight : node_weights)
|
||||||
|
{
|
||||||
|
weight = (weight & 0x80000000) ? INVALID_EDGE_WEIGHT : weight;
|
||||||
|
}
|
||||||
|
|
||||||
// Contracting the edge-expanded graph
|
// Contracting the edge-expanded graph
|
||||||
|
|
||||||
TIMER_START(contraction);
|
TIMER_START(contraction);
|
||||||
@@ -96,6 +102,7 @@ int Contractor::Run()
|
|||||||
QueryGraph query_graph;
|
QueryGraph query_graph;
|
||||||
std::vector<std::vector<bool>> edge_filters;
|
std::vector<std::vector<bool>> edge_filters;
|
||||||
std::vector<std::vector<bool>> cores;
|
std::vector<std::vector<bool>> cores;
|
||||||
|
|
||||||
std::tie(query_graph, edge_filters) = contractExcludableGraph(
|
std::tie(query_graph, edge_filters) = contractExcludableGraph(
|
||||||
toContractorGraph(number_of_edge_based_nodes, std::move(edge_based_edge_list)),
|
toContractorGraph(number_of_edge_based_nodes, std::move(edge_based_edge_list)),
|
||||||
std::move(node_weights),
|
std::move(node_weights),
|
||||||
|
|||||||
@@ -215,6 +215,7 @@ void ContractNode(ContractorThreadData *data,
|
|||||||
target,
|
target,
|
||||||
path_weight,
|
path_weight,
|
||||||
in_data.duration + out_data.duration,
|
in_data.duration + out_data.duration,
|
||||||
|
in_data.distance + out_data.distance,
|
||||||
out_data.originalEdges + in_data.originalEdges,
|
out_data.originalEdges + in_data.originalEdges,
|
||||||
node,
|
node,
|
||||||
SHORTCUT_ARC,
|
SHORTCUT_ARC,
|
||||||
@@ -225,6 +226,7 @@ void ContractNode(ContractorThreadData *data,
|
|||||||
source,
|
source,
|
||||||
path_weight,
|
path_weight,
|
||||||
in_data.duration + out_data.duration,
|
in_data.duration + out_data.duration,
|
||||||
|
in_data.distance + out_data.distance,
|
||||||
out_data.originalEdges + in_data.originalEdges,
|
out_data.originalEdges + in_data.originalEdges,
|
||||||
node,
|
node,
|
||||||
SHORTCUT_ARC,
|
SHORTCUT_ARC,
|
||||||
@@ -280,6 +282,7 @@ void ContractNode(ContractorThreadData *data,
|
|||||||
target,
|
target,
|
||||||
path_weight,
|
path_weight,
|
||||||
in_data.duration + out_data.duration,
|
in_data.duration + out_data.duration,
|
||||||
|
in_data.distance + out_data.distance,
|
||||||
out_data.originalEdges + in_data.originalEdges,
|
out_data.originalEdges + in_data.originalEdges,
|
||||||
node,
|
node,
|
||||||
SHORTCUT_ARC,
|
SHORTCUT_ARC,
|
||||||
@@ -290,6 +293,7 @@ void ContractNode(ContractorThreadData *data,
|
|||||||
source,
|
source,
|
||||||
path_weight,
|
path_weight,
|
||||||
in_data.duration + out_data.duration,
|
in_data.duration + out_data.duration,
|
||||||
|
in_data.distance + out_data.distance,
|
||||||
out_data.originalEdges + in_data.originalEdges,
|
out_data.originalEdges + in_data.originalEdges,
|
||||||
node,
|
node,
|
||||||
SHORTCUT_ARC,
|
SHORTCUT_ARC,
|
||||||
@@ -556,7 +560,7 @@ bool IsNodeIndependent(const util::XORFastHash<> &hash,
|
|||||||
}
|
}
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
}
|
} // namespace
|
||||||
|
|
||||||
std::vector<bool> contractGraph(ContractorGraph &graph,
|
std::vector<bool> contractGraph(ContractorGraph &graph,
|
||||||
std::vector<bool> node_is_uncontracted_,
|
std::vector<bool> node_is_uncontracted_,
|
||||||
|
|||||||
@@ -74,24 +74,28 @@ void printUnreachableStatistics(const Partition &partition,
|
|||||||
|
|
||||||
auto LoadAndUpdateEdgeExpandedGraph(const CustomizationConfig &config,
|
auto LoadAndUpdateEdgeExpandedGraph(const CustomizationConfig &config,
|
||||||
const partitioner::MultiLevelPartition &mlp,
|
const partitioner::MultiLevelPartition &mlp,
|
||||||
|
std::vector<EdgeWeight> &node_weights,
|
||||||
|
std::vector<EdgeDuration> &node_durations,
|
||||||
std::uint32_t &connectivity_checksum)
|
std::uint32_t &connectivity_checksum)
|
||||||
{
|
{
|
||||||
updater::Updater updater(config.updater_config);
|
updater::Updater updater(config.updater_config);
|
||||||
|
|
||||||
EdgeID num_nodes;
|
|
||||||
std::vector<extractor::EdgeBasedEdge> edge_based_edge_list;
|
std::vector<extractor::EdgeBasedEdge> edge_based_edge_list;
|
||||||
std::tie(num_nodes, edge_based_edge_list, connectivity_checksum) =
|
EdgeID num_nodes = updater.LoadAndUpdateEdgeExpandedGraph(
|
||||||
updater.LoadAndUpdateEdgeExpandedGraph();
|
edge_based_edge_list, node_weights, node_durations, connectivity_checksum);
|
||||||
|
|
||||||
auto directed = partitioner::splitBidirectionalEdges(edge_based_edge_list);
|
auto directed = partitioner::splitBidirectionalEdges(edge_based_edge_list);
|
||||||
auto tidied =
|
|
||||||
partitioner::prepareEdgesForUsageInGraph<StaticEdgeBasedGraphEdge>(std::move(directed));
|
auto tidied = partitioner::prepareEdgesForUsageInGraph<
|
||||||
auto edge_based_graph = customizer::MultiLevelEdgeBasedGraph(mlp, num_nodes, std::move(tidied));
|
typename partitioner::MultiLevelEdgeBasedGraph::InputEdge>(std::move(directed));
|
||||||
|
|
||||||
|
auto edge_based_graph =
|
||||||
|
partitioner::MultiLevelEdgeBasedGraph(mlp, num_nodes, std::move(tidied));
|
||||||
|
|
||||||
return edge_based_graph;
|
return edge_based_graph;
|
||||||
}
|
}
|
||||||
|
|
||||||
std::vector<CellMetric> customizeFilteredMetrics(const MultiLevelEdgeBasedGraph &graph,
|
std::vector<CellMetric> customizeFilteredMetrics(const partitioner::MultiLevelEdgeBasedGraph &graph,
|
||||||
const partitioner::CellStorage &storage,
|
const partitioner::CellStorage &storage,
|
||||||
const CellCustomizer &customizer,
|
const CellCustomizer &customizer,
|
||||||
const std::vector<std::vector<bool>> &node_filters)
|
const std::vector<std::vector<bool>> &node_filters)
|
||||||
@@ -119,8 +123,13 @@ int Customizer::Run(const CustomizationConfig &config)
|
|||||||
partitioner::MultiLevelPartition mlp;
|
partitioner::MultiLevelPartition mlp;
|
||||||
partitioner::files::readPartition(config.GetPath(".osrm.partition"), mlp);
|
partitioner::files::readPartition(config.GetPath(".osrm.partition"), mlp);
|
||||||
|
|
||||||
|
std::vector<EdgeWeight> node_weights;
|
||||||
|
std::vector<EdgeDuration> node_durations; // TODO: to be removed later
|
||||||
std::uint32_t connectivity_checksum = 0;
|
std::uint32_t connectivity_checksum = 0;
|
||||||
auto graph = LoadAndUpdateEdgeExpandedGraph(config, mlp, connectivity_checksum);
|
auto graph = LoadAndUpdateEdgeExpandedGraph(
|
||||||
|
config, mlp, node_weights, node_durations, connectivity_checksum);
|
||||||
|
BOOST_ASSERT(graph.GetNumberOfNodes() == node_weights.size());
|
||||||
|
std::for_each(node_weights.begin(), node_weights.end(), [](auto &w) { w &= 0x7fffffff; });
|
||||||
util::Log() << "Loaded edge based graph: " << graph.GetNumberOfEdges() << " edges, "
|
util::Log() << "Loaded edge based graph: " << graph.GetNumberOfEdges() << " edges, "
|
||||||
<< graph.GetNumberOfNodes() << " nodes";
|
<< graph.GetNumberOfNodes() << " nodes";
|
||||||
|
|
||||||
@@ -157,7 +166,10 @@ int Customizer::Run(const CustomizationConfig &config)
|
|||||||
util::Log() << "MLD customization writing took " << TIMER_SEC(writing_mld_data) << " seconds";
|
util::Log() << "MLD customization writing took " << TIMER_SEC(writing_mld_data) << " seconds";
|
||||||
|
|
||||||
TIMER_START(writing_graph);
|
TIMER_START(writing_graph);
|
||||||
partitioner::files::writeGraph(config.GetPath(".osrm.mldgr"), graph, connectivity_checksum);
|
MultiLevelEdgeBasedGraph shaved_graph{
|
||||||
|
std::move(graph), std::move(node_weights), std::move(node_durations)};
|
||||||
|
customizer::files::writeGraph(
|
||||||
|
config.GetPath(".osrm.mldgr"), shaved_graph, connectivity_checksum);
|
||||||
TIMER_STOP(writing_graph);
|
TIMER_STOP(writing_graph);
|
||||||
util::Log() << "Graph writing took " << TIMER_SEC(writing_graph) << " seconds";
|
util::Log() << "Graph writing took " << TIMER_SEC(writing_graph) << " seconds";
|
||||||
|
|
||||||
|
|||||||
@@ -618,9 +618,11 @@ RouteSteps collapseSegregatedTurnInstructions(RouteSteps steps)
|
|||||||
TransferLanesStrategy());
|
TransferLanesStrategy());
|
||||||
++next_step;
|
++next_step;
|
||||||
}
|
}
|
||||||
// else if the current step is segregated and the next step is not then combine with turn
|
// else if the current step is segregated and the next step is not segregated
|
||||||
// adjustment
|
// and the next step is not a roundabout then combine with turn adjustment
|
||||||
else if (curr_step->is_segregated && !next_step->is_segregated)
|
else if (curr_step->is_segregated && !next_step->is_segregated &&
|
||||||
|
!hasRoundaboutType(curr_step->maneuver.instruction) &&
|
||||||
|
!hasRoundaboutType(next_step->maneuver.instruction))
|
||||||
{
|
{
|
||||||
// Determine if u-turn
|
// Determine if u-turn
|
||||||
if (bearingsAreReversed(
|
if (bearingsAreReversed(
|
||||||
|
|||||||
@@ -81,16 +81,21 @@ Status TablePlugin::HandleRequest(const RoutingAlgorithmsInterface &algorithms,
|
|||||||
}
|
}
|
||||||
|
|
||||||
auto snapped_phantoms = SnapPhantomNodes(phantom_nodes);
|
auto snapped_phantoms = SnapPhantomNodes(phantom_nodes);
|
||||||
auto result_table =
|
|
||||||
algorithms.ManyToManySearch(snapped_phantoms, params.sources, params.destinations);
|
|
||||||
|
|
||||||
if (result_table.empty())
|
bool request_distance = params.annotations & api::TableParameters::AnnotationsType::Distance;
|
||||||
|
bool request_duration = params.annotations & api::TableParameters::AnnotationsType::Duration;
|
||||||
|
|
||||||
|
auto result_tables_pair = algorithms.ManyToManySearch(
|
||||||
|
snapped_phantoms, params.sources, params.destinations, request_distance, request_duration);
|
||||||
|
|
||||||
|
if ((request_duration && result_tables_pair.first.empty()) ||
|
||||||
|
(request_distance && result_tables_pair.second.empty()))
|
||||||
{
|
{
|
||||||
return Error("NoTable", "No table found", result);
|
return Error("NoTable", "No table found", result);
|
||||||
}
|
}
|
||||||
|
|
||||||
api::TableAPI table_api{facade, params};
|
api::TableAPI table_api{facade, params};
|
||||||
table_api.MakeResponse(result_table, snapped_phantoms, result);
|
table_api.MakeResponse(result_tables_pair, snapped_phantoms, result);
|
||||||
|
|
||||||
return Status::Ok;
|
return Status::Ok;
|
||||||
}
|
}
|
||||||
|
|||||||
+212
-540
@@ -1,5 +1,6 @@
|
|||||||
#include "guidance/turn_instruction.hpp"
|
#include "guidance/turn_instruction.hpp"
|
||||||
|
|
||||||
|
#include "engine/plugins/plugin_base.hpp"
|
||||||
#include "engine/plugins/plugin_base.hpp"
|
#include "engine/plugins/plugin_base.hpp"
|
||||||
#include "engine/plugins/tile.hpp"
|
#include "engine/plugins/tile.hpp"
|
||||||
|
|
||||||
@@ -8,21 +9,19 @@
|
|||||||
#include "util/vector_tile.hpp"
|
#include "util/vector_tile.hpp"
|
||||||
#include "util/web_mercator.hpp"
|
#include "util/web_mercator.hpp"
|
||||||
|
|
||||||
#include "engine/api/json_factory.hpp"
|
|
||||||
|
|
||||||
#include <boost/geometry.hpp>
|
#include <boost/geometry.hpp>
|
||||||
#include <boost/geometry/geometries/geometries.hpp>
|
#include <boost/geometry/geometries/geometries.hpp>
|
||||||
#include <boost/geometry/geometries/point_xy.hpp>
|
#include <boost/geometry/geometries/point_xy.hpp>
|
||||||
#include <boost/geometry/multi/geometries/multi_linestring.hpp>
|
#include <boost/geometry/multi/geometries/multi_linestring.hpp>
|
||||||
|
|
||||||
#include <protozero/pbf_writer.hpp>
|
#include <vtzero/builder.hpp>
|
||||||
#include <protozero/varint.hpp>
|
#include <vtzero/geometry.hpp>
|
||||||
|
#include <vtzero/index.hpp>
|
||||||
|
|
||||||
#include <algorithm>
|
#include <algorithm>
|
||||||
#include <numeric>
|
#include <numeric>
|
||||||
#include <string>
|
#include <string>
|
||||||
#include <unordered_map>
|
#include <unordered_map>
|
||||||
#include <unordered_set>
|
|
||||||
#include <utility>
|
#include <utility>
|
||||||
#include <vector>
|
#include <vector>
|
||||||
|
|
||||||
@@ -41,45 +40,7 @@ constexpr const static int MIN_ZOOM_FOR_TURNS = 15;
|
|||||||
namespace
|
namespace
|
||||||
{
|
{
|
||||||
|
|
||||||
// Creates an indexed lookup table for values - used to encoded the vector tile
|
|
||||||
// which uses a lookup table and index pointers for encoding
|
|
||||||
template <typename T> struct ValueIndexer
|
|
||||||
{
|
|
||||||
private:
|
|
||||||
std::vector<T> used_values;
|
|
||||||
std::unordered_map<T, std::size_t> value_offsets;
|
|
||||||
|
|
||||||
public:
|
|
||||||
std::size_t add(const T &value)
|
|
||||||
{
|
|
||||||
const auto found = value_offsets.find(value);
|
|
||||||
std::size_t offset;
|
|
||||||
|
|
||||||
if (found == value_offsets.end())
|
|
||||||
{
|
|
||||||
used_values.push_back(value);
|
|
||||||
offset = used_values.size() - 1;
|
|
||||||
value_offsets[value] = offset;
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
offset = found->second;
|
|
||||||
}
|
|
||||||
|
|
||||||
return offset;
|
|
||||||
}
|
|
||||||
|
|
||||||
std::size_t indexOf(const T &value) { return value_offsets[value]; }
|
|
||||||
|
|
||||||
const std::vector<T> &values() { return used_values; }
|
|
||||||
|
|
||||||
std::size_t size() const { return used_values.size(); }
|
|
||||||
};
|
|
||||||
|
|
||||||
using RTreeLeaf = datafacade::BaseDataFacade::RTreeLeaf;
|
using RTreeLeaf = datafacade::BaseDataFacade::RTreeLeaf;
|
||||||
// TODO: Port all this encoding logic to https://github.com/mapbox/vector-tile, which wasn't
|
|
||||||
// available when this code was originally written.
|
|
||||||
|
|
||||||
// Simple container class for WGS84 coordinates
|
// Simple container class for WGS84 coordinates
|
||||||
template <typename T> struct Point final
|
template <typename T> struct Point final
|
||||||
{
|
{
|
||||||
@@ -132,58 +93,15 @@ const static box_t clip_box(point_t(-util::vector_tile::BUFFER, -util::vector_ti
|
|||||||
point_t(util::vector_tile::EXTENT + util::vector_tile::BUFFER,
|
point_t(util::vector_tile::EXTENT + util::vector_tile::BUFFER,
|
||||||
util::vector_tile::EXTENT + util::vector_tile::BUFFER));
|
util::vector_tile::EXTENT + util::vector_tile::BUFFER));
|
||||||
|
|
||||||
// from mapnik-vector-tile
|
/**
|
||||||
// Encodes a linestring using protobuf zigzag encoding
|
* Return the x1,y1,x2,y2 pixel coordinates of a line in a given
|
||||||
inline bool encodeLinestring(const FixedLine &line,
|
* tile.
|
||||||
protozero::packed_field_uint32 &geometry,
|
*
|
||||||
std::int32_t &start_x,
|
* @param start the first coordinate of the line
|
||||||
std::int32_t &start_y)
|
* @param target the last coordinate of the line
|
||||||
{
|
* @param tile_bbox the boundaries of the tile, in mercator coordinates
|
||||||
const std::size_t line_size = line.size();
|
* @return a FixedLine with coordinates relative to the tile_bbox.
|
||||||
if (line_size < 2)
|
*/
|
||||||
{
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
const unsigned lineto_count = static_cast<const unsigned>(line_size) - 1;
|
|
||||||
|
|
||||||
auto pt = line.begin();
|
|
||||||
const constexpr int MOVETO_COMMAND = 9;
|
|
||||||
geometry.add_element(MOVETO_COMMAND); // move_to | (1 << 3)
|
|
||||||
geometry.add_element(protozero::encode_zigzag32(pt->x - start_x));
|
|
||||||
geometry.add_element(protozero::encode_zigzag32(pt->y - start_y));
|
|
||||||
start_x = pt->x;
|
|
||||||
start_y = pt->y;
|
|
||||||
// This means LINETO repeated N times
|
|
||||||
// See: https://github.com/mapbox/vector-tile-spec/tree/master/2.1#example-command-integers
|
|
||||||
geometry.add_element((lineto_count << 3u) | 2u);
|
|
||||||
// Now that we've issued the LINETO REPEAT N command, we append
|
|
||||||
// N coordinate pairs immediately after the command.
|
|
||||||
for (++pt; pt != line.end(); ++pt)
|
|
||||||
{
|
|
||||||
const std::int32_t dx = pt->x - start_x;
|
|
||||||
const std::int32_t dy = pt->y - start_y;
|
|
||||||
geometry.add_element(protozero::encode_zigzag32(dx));
|
|
||||||
geometry.add_element(protozero::encode_zigzag32(dy));
|
|
||||||
start_x = pt->x;
|
|
||||||
start_y = pt->y;
|
|
||||||
}
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
|
|
||||||
// from mapnik-vctor-tile
|
|
||||||
// Encodes a point
|
|
||||||
inline void encodePoint(const FixedPoint &pt, protozero::packed_field_uint32 &geometry)
|
|
||||||
{
|
|
||||||
const constexpr int MOVETO_COMMAND = 9;
|
|
||||||
geometry.add_element(MOVETO_COMMAND);
|
|
||||||
const std::int32_t dx = pt.x;
|
|
||||||
const std::int32_t dy = pt.y;
|
|
||||||
// Manual zigzag encoding.
|
|
||||||
geometry.add_element(protozero::encode_zigzag32(dx));
|
|
||||||
geometry.add_element(protozero::encode_zigzag32(dy));
|
|
||||||
}
|
|
||||||
|
|
||||||
linestring_t floatLineToTileLine(const FloatLine &geo_line, const BBox &tile_bbox)
|
linestring_t floatLineToTileLine(const FloatLine &geo_line, const BBox &tile_bbox)
|
||||||
{
|
{
|
||||||
linestring_t unclipped_line;
|
linestring_t unclipped_line;
|
||||||
@@ -361,6 +279,144 @@ std::vector<NodeID> getSegregatedNodes(const DataFacadeBase &facade,
|
|||||||
return result;
|
return result;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
struct SpeedLayer : public vtzero::layer_builder
|
||||||
|
{
|
||||||
|
|
||||||
|
vtzero::value_index_small_uint uint_index;
|
||||||
|
vtzero::value_index<vtzero::double_value_type, float, std::unordered_map> double_index;
|
||||||
|
vtzero::value_index_internal<std::unordered_map> string_index;
|
||||||
|
vtzero::value_index_bool bool_index;
|
||||||
|
|
||||||
|
vtzero::index_value key_speed;
|
||||||
|
vtzero::index_value key_is_small;
|
||||||
|
vtzero::index_value key_datasource;
|
||||||
|
vtzero::index_value key_weight;
|
||||||
|
vtzero::index_value key_duration;
|
||||||
|
vtzero::index_value key_name;
|
||||||
|
vtzero::index_value key_rate;
|
||||||
|
|
||||||
|
SpeedLayer(vtzero::tile_builder &tile)
|
||||||
|
: layer_builder(tile, "speeds"), uint_index(*this), double_index(*this),
|
||||||
|
string_index(*this), bool_index(*this), key_speed(add_key_without_dup_check("speed")),
|
||||||
|
key_is_small(add_key_without_dup_check("is_small")),
|
||||||
|
key_datasource(add_key_without_dup_check("datasource")),
|
||||||
|
key_weight(add_key_without_dup_check("weight")),
|
||||||
|
key_duration(add_key_without_dup_check("duration")),
|
||||||
|
key_name(add_key_without_dup_check("name")), key_rate(add_key_without_dup_check("rate"))
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
|
}; // struct SpeedLayer
|
||||||
|
|
||||||
|
class SpeedLayerFeatureBuilder : public vtzero::linestring_feature_builder
|
||||||
|
{
|
||||||
|
|
||||||
|
SpeedLayer &m_layer;
|
||||||
|
|
||||||
|
public:
|
||||||
|
SpeedLayerFeatureBuilder(SpeedLayer &layer, uint64_t id)
|
||||||
|
: vtzero::linestring_feature_builder(layer), m_layer(layer)
|
||||||
|
{
|
||||||
|
set_id(id);
|
||||||
|
}
|
||||||
|
|
||||||
|
void set_speed(unsigned int value)
|
||||||
|
{
|
||||||
|
add_property(m_layer.key_speed, m_layer.uint_index(std::min(value, 127u)));
|
||||||
|
}
|
||||||
|
|
||||||
|
void set_is_small(bool value) { add_property(m_layer.key_is_small, m_layer.bool_index(value)); }
|
||||||
|
|
||||||
|
void set_datasource(const std::string &value)
|
||||||
|
{
|
||||||
|
add_property(m_layer.key_datasource,
|
||||||
|
m_layer.string_index(vtzero::encoded_property_value{value}));
|
||||||
|
}
|
||||||
|
|
||||||
|
void set_weight(double value) { add_property(m_layer.key_weight, m_layer.double_index(value)); }
|
||||||
|
|
||||||
|
void set_duration(double value)
|
||||||
|
{
|
||||||
|
add_property(m_layer.key_duration, m_layer.double_index(value));
|
||||||
|
}
|
||||||
|
|
||||||
|
void set_name(const boost::string_ref &value)
|
||||||
|
{
|
||||||
|
add_property(
|
||||||
|
m_layer.key_name,
|
||||||
|
m_layer.string_index(vtzero::encoded_property_value{value.data(), value.size()}));
|
||||||
|
}
|
||||||
|
|
||||||
|
void set_rate(double value) { add_property(m_layer.key_rate, m_layer.double_index(value)); }
|
||||||
|
|
||||||
|
}; // class SpeedLayerFeatureBuilder
|
||||||
|
|
||||||
|
struct TurnsLayer : public vtzero::layer_builder
|
||||||
|
{
|
||||||
|
|
||||||
|
vtzero::value_index<vtzero::sint_value_type, int, std::unordered_map> int_index;
|
||||||
|
vtzero::value_index<vtzero::float_value_type, float, std::unordered_map> float_index;
|
||||||
|
vtzero::value_index_internal<std::unordered_map> string_index;
|
||||||
|
|
||||||
|
vtzero::index_value key_bearing_in;
|
||||||
|
vtzero::index_value key_turn_angle;
|
||||||
|
vtzero::index_value key_cost;
|
||||||
|
vtzero::index_value key_weight;
|
||||||
|
vtzero::index_value key_turn_type;
|
||||||
|
vtzero::index_value key_turn_modifier;
|
||||||
|
|
||||||
|
TurnsLayer(vtzero::tile_builder &tile)
|
||||||
|
: layer_builder(tile, "turns"), int_index(*this), float_index(*this), string_index(*this),
|
||||||
|
key_bearing_in(add_key_without_dup_check("bearing_in")),
|
||||||
|
key_turn_angle(add_key_without_dup_check("turn_angle")),
|
||||||
|
key_cost(add_key_without_dup_check("cost")),
|
||||||
|
key_weight(add_key_without_dup_check("weight")),
|
||||||
|
key_turn_type(add_key_without_dup_check("type")),
|
||||||
|
key_turn_modifier(add_key_without_dup_check("modifier"))
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
|
}; // struct TurnsLayer
|
||||||
|
|
||||||
|
class TurnsLayerFeatureBuilder : public vtzero::point_feature_builder
|
||||||
|
{
|
||||||
|
|
||||||
|
TurnsLayer &m_layer;
|
||||||
|
|
||||||
|
public:
|
||||||
|
TurnsLayerFeatureBuilder(TurnsLayer &layer, uint64_t id)
|
||||||
|
: vtzero::point_feature_builder(layer), m_layer(layer)
|
||||||
|
{
|
||||||
|
set_id(id);
|
||||||
|
}
|
||||||
|
|
||||||
|
void set_bearing_in(int value)
|
||||||
|
{
|
||||||
|
add_property(m_layer.key_bearing_in, m_layer.int_index(value));
|
||||||
|
}
|
||||||
|
|
||||||
|
void set_turn_angle(int value)
|
||||||
|
{
|
||||||
|
add_property(m_layer.key_turn_angle, m_layer.int_index(value));
|
||||||
|
}
|
||||||
|
|
||||||
|
void set_cost(float value) { add_property(m_layer.key_cost, m_layer.float_index(value)); }
|
||||||
|
|
||||||
|
void set_weight(float value) { add_property(m_layer.key_weight, m_layer.float_index(value)); }
|
||||||
|
|
||||||
|
void set_turn(osrm::guidance::TurnInstruction value)
|
||||||
|
{
|
||||||
|
const auto type = osrm::guidance::internalInstructionTypeToString(value.type);
|
||||||
|
const auto modifier = osrm::guidance::instructionModifierToString(value.direction_modifier);
|
||||||
|
add_property(
|
||||||
|
m_layer.key_turn_type,
|
||||||
|
m_layer.string_index(vtzero::encoded_property_value{type.data(), type.size()}));
|
||||||
|
add_property(
|
||||||
|
m_layer.key_turn_modifier,
|
||||||
|
m_layer.string_index(vtzero::encoded_property_value{modifier.data(), modifier.size()}));
|
||||||
|
}
|
||||||
|
}; // class TurnsLayerFeatureBuilder
|
||||||
|
|
||||||
void encodeVectorTile(const DataFacadeBase &facade,
|
void encodeVectorTile(const DataFacadeBase &facade,
|
||||||
unsigned x,
|
unsigned x,
|
||||||
unsigned y,
|
unsigned y,
|
||||||
@@ -371,117 +427,25 @@ void encodeVectorTile(const DataFacadeBase &facade,
|
|||||||
const std::vector<NodeID> &segregated_nodes,
|
const std::vector<NodeID> &segregated_nodes,
|
||||||
std::string &pbf_buffer)
|
std::string &pbf_buffer)
|
||||||
{
|
{
|
||||||
|
vtzero::tile_builder tile;
|
||||||
std::uint8_t max_datasource_id = 0;
|
|
||||||
|
|
||||||
// Vector tiles encode properties on features as indexes into a layer-specific
|
|
||||||
// lookup table. These ValueIndexer's act as memoizers for values as we discover
|
|
||||||
// them during edge explioration, and are then used to generate the lookup
|
|
||||||
// tables for each tile layer.
|
|
||||||
ValueIndexer<int> line_int_index;
|
|
||||||
ValueIndexer<util::StringView> line_string_index;
|
|
||||||
ValueIndexer<int> point_int_index;
|
|
||||||
ValueIndexer<float> point_float_index;
|
|
||||||
ValueIndexer<std::string> point_string_index;
|
|
||||||
|
|
||||||
const auto get_geometry_id = [&facade](auto edge) {
|
const auto get_geometry_id = [&facade](auto edge) {
|
||||||
return facade.GetGeometryIndex(edge.forward_segment_id.id).id;
|
return facade.GetGeometryIndex(edge.forward_segment_id.id).id;
|
||||||
};
|
};
|
||||||
|
|
||||||
// Vector tiles encode feature properties as indexes into a lookup table. So, we need
|
|
||||||
// to "pre-loop" over all the edges to create the lookup tables. Once we have those, we
|
|
||||||
// can then encode the features, and we'll know the indexes that feature properties
|
|
||||||
// need to refer to.
|
|
||||||
for (const auto &edge_index : sorted_edge_indexes)
|
|
||||||
{
|
|
||||||
const auto &edge = edges[edge_index];
|
|
||||||
|
|
||||||
const auto geometry_id = get_geometry_id(edge);
|
|
||||||
const auto forward_datasource_range = facade.GetUncompressedForwardDatasources(geometry_id);
|
|
||||||
const auto reverse_datasource_range = facade.GetUncompressedReverseDatasources(geometry_id);
|
|
||||||
|
|
||||||
BOOST_ASSERT(edge.fwd_segment_position < forward_datasource_range.size());
|
|
||||||
const auto forward_datasource = forward_datasource_range(edge.fwd_segment_position);
|
|
||||||
BOOST_ASSERT(edge.fwd_segment_position < reverse_datasource_range.size());
|
|
||||||
const auto reverse_datasource = reverse_datasource_range(reverse_datasource_range.size() -
|
|
||||||
edge.fwd_segment_position - 1);
|
|
||||||
|
|
||||||
// Keep track of the highest datasource seen so that we don't write unnecessary
|
|
||||||
// data to the layer attribute values
|
|
||||||
max_datasource_id = std::max(max_datasource_id, forward_datasource);
|
|
||||||
max_datasource_id = std::max(max_datasource_id, reverse_datasource);
|
|
||||||
}
|
|
||||||
|
|
||||||
// Convert tile coordinates into mercator coordinates
|
// Convert tile coordinates into mercator coordinates
|
||||||
double min_mercator_lon, min_mercator_lat, max_mercator_lon, max_mercator_lat;
|
double min_mercator_lon, min_mercator_lat, max_mercator_lon, max_mercator_lat;
|
||||||
util::web_mercator::xyzToMercator(
|
util::web_mercator::xyzToMercator(
|
||||||
x, y, z, min_mercator_lon, min_mercator_lat, max_mercator_lon, max_mercator_lat);
|
x, y, z, min_mercator_lon, min_mercator_lat, max_mercator_lon, max_mercator_lat);
|
||||||
const BBox tile_bbox{min_mercator_lon, min_mercator_lat, max_mercator_lon, max_mercator_lat};
|
const BBox tile_bbox{min_mercator_lon, min_mercator_lat, max_mercator_lon, max_mercator_lat};
|
||||||
|
|
||||||
// Protobuf serializes blocks when objects go out of scope, hence
|
// XXX leaving in some superfluous scopes to make diff easier to read.
|
||||||
// the extra scoping below.
|
|
||||||
protozero::pbf_writer tile_writer{pbf_buffer};
|
|
||||||
{
|
{
|
||||||
{
|
{
|
||||||
// Add a layer object to the PBF stream. 3=='layer' from the vector tile spec
|
|
||||||
// (2.1)
|
|
||||||
protozero::pbf_writer line_layer_writer(tile_writer, util::vector_tile::LAYER_TAG);
|
|
||||||
// TODO: don't write a layer if there are no features
|
|
||||||
|
|
||||||
line_layer_writer.add_uint32(util::vector_tile::VERSION_TAG, 2); // version
|
|
||||||
// Field 1 is the "layer name" field, it's a string
|
|
||||||
line_layer_writer.add_string(util::vector_tile::NAME_TAG, "speeds"); // name
|
|
||||||
// Field 5 is the tile extent. It's a uint32 and should be set to 4096
|
|
||||||
// for normal vector tiles.
|
|
||||||
line_layer_writer.add_uint32(util::vector_tile::EXTENT_TAG,
|
|
||||||
util::vector_tile::EXTENT); // extent
|
|
||||||
|
|
||||||
// Because we need to know the indexes into the vector tile lookup table,
|
|
||||||
// we need to do an initial pass over the data and create the complete
|
|
||||||
// index of used values.
|
|
||||||
for (const auto &edge_index : sorted_edge_indexes)
|
|
||||||
{
|
|
||||||
const auto &edge = edges[edge_index];
|
|
||||||
const auto geometry_id = get_geometry_id(edge);
|
|
||||||
|
|
||||||
// Get coordinates for start/end nodes of segment (NodeIDs u and v)
|
|
||||||
const auto a = facade.GetCoordinateOfNode(edge.u);
|
|
||||||
const auto b = facade.GetCoordinateOfNode(edge.v);
|
|
||||||
// Calculate the length in meters
|
|
||||||
const double length = osrm::util::coordinate_calculation::haversineDistance(a, b);
|
|
||||||
|
|
||||||
// Weight values
|
|
||||||
const auto forward_weight_range = facade.GetUncompressedForwardWeights(geometry_id);
|
|
||||||
const auto reverse_weight_range = facade.GetUncompressedReverseWeights(geometry_id);
|
|
||||||
const auto forward_weight = forward_weight_range[edge.fwd_segment_position];
|
|
||||||
const auto reverse_weight = reverse_weight_range[reverse_weight_range.size() -
|
|
||||||
edge.fwd_segment_position - 1];
|
|
||||||
line_int_index.add(forward_weight);
|
|
||||||
line_int_index.add(reverse_weight);
|
|
||||||
|
|
||||||
std::uint32_t forward_rate =
|
|
||||||
static_cast<std::uint32_t>(round(length / forward_weight * 10.));
|
|
||||||
std::uint32_t reverse_rate =
|
|
||||||
static_cast<std::uint32_t>(round(length / reverse_weight * 10.));
|
|
||||||
|
|
||||||
line_int_index.add(forward_rate);
|
|
||||||
line_int_index.add(reverse_rate);
|
|
||||||
|
|
||||||
// Duration values
|
|
||||||
const auto forward_duration_range =
|
|
||||||
facade.GetUncompressedForwardDurations(geometry_id);
|
|
||||||
const auto reverse_duration_range =
|
|
||||||
facade.GetUncompressedReverseDurations(geometry_id);
|
|
||||||
const auto forward_duration = forward_duration_range[edge.fwd_segment_position];
|
|
||||||
const auto reverse_duration = reverse_duration_range[reverse_duration_range.size() -
|
|
||||||
edge.fwd_segment_position - 1];
|
|
||||||
|
|
||||||
line_int_index.add(forward_duration);
|
|
||||||
line_int_index.add(reverse_duration);
|
|
||||||
}
|
|
||||||
|
|
||||||
// Begin the layer features block
|
// Begin the layer features block
|
||||||
{
|
{
|
||||||
|
SpeedLayer speeds_layer{tile};
|
||||||
|
|
||||||
// Each feature gets a unique id, starting at 1
|
// Each feature gets a unique id, starting at 1
|
||||||
unsigned id = 1;
|
unsigned id = 1;
|
||||||
for (const auto &edge_index : sorted_edge_indexes)
|
for (const auto &edge_index : sorted_edge_indexes)
|
||||||
@@ -516,7 +480,6 @@ void encodeVectorTile(const DataFacadeBase &facade,
|
|||||||
const auto reverse_duration =
|
const auto reverse_duration =
|
||||||
reverse_duration_range[reverse_duration_range.size() -
|
reverse_duration_range[reverse_duration_range.size() -
|
||||||
edge.fwd_segment_position - 1];
|
edge.fwd_segment_position - 1];
|
||||||
|
|
||||||
const auto forward_datasource_idx =
|
const auto forward_datasource_idx =
|
||||||
forward_datasource_range(edge.fwd_segment_position);
|
forward_datasource_range(edge.fwd_segment_position);
|
||||||
const auto reverse_datasource_idx = reverse_datasource_range(
|
const auto reverse_datasource_idx = reverse_datasource_range(
|
||||||
@@ -526,84 +489,10 @@ void encodeVectorTile(const DataFacadeBase &facade,
|
|||||||
const auto name_id = facade.GetNameIndex(edge.forward_segment_id.id);
|
const auto name_id = facade.GetNameIndex(edge.forward_segment_id.id);
|
||||||
auto name = facade.GetNameForID(name_id);
|
auto name = facade.GetNameForID(name_id);
|
||||||
|
|
||||||
line_string_index.add(name);
|
|
||||||
|
|
||||||
const auto encode_tile_line = [&line_layer_writer,
|
|
||||||
&component_id,
|
|
||||||
&id,
|
|
||||||
&max_datasource_id,
|
|
||||||
&line_int_index](
|
|
||||||
const FixedLine &tile_line,
|
|
||||||
const std::uint32_t speed_kmh_idx,
|
|
||||||
const std::uint32_t rate_idx,
|
|
||||||
const std::size_t weight_idx,
|
|
||||||
const std::size_t duration_idx,
|
|
||||||
const DatasourceID datasource_idx,
|
|
||||||
const std::size_t name_idx,
|
|
||||||
std::int32_t &start_x,
|
|
||||||
std::int32_t &start_y) {
|
|
||||||
// Here, we save the two attributes for our feature: the speed and
|
|
||||||
// the is_small boolean. We only serve up speeds from 0-139, so all we
|
|
||||||
// do is save the first
|
|
||||||
protozero::pbf_writer feature_writer(line_layer_writer,
|
|
||||||
util::vector_tile::FEATURE_TAG);
|
|
||||||
// Field 3 is the "geometry type" field. Value 2 is "line"
|
|
||||||
feature_writer.add_enum(
|
|
||||||
util::vector_tile::GEOMETRY_TAG,
|
|
||||||
util::vector_tile::GEOMETRY_TYPE_LINE); // geometry type
|
|
||||||
// Field 1 for the feature is the "id" field.
|
|
||||||
feature_writer.add_uint64(util::vector_tile::ID_TAG, id++); // id
|
|
||||||
{
|
|
||||||
// When adding attributes to a feature, we have to write
|
|
||||||
// pairs of numbers. The first value is the index in the
|
|
||||||
// keys array (written later), and the second value is the
|
|
||||||
// index into the "values" array (also written later). We're
|
|
||||||
// not writing the actual speed or bool value here, we're saving
|
|
||||||
// an index into the "values" array. This means many features
|
|
||||||
// can share the same value data, leading to smaller tiles.
|
|
||||||
protozero::packed_field_uint32 field(
|
|
||||||
feature_writer, util::vector_tile::FEATURE_ATTRIBUTES_TAG);
|
|
||||||
|
|
||||||
field.add_element(0); // "speed" tag key offset
|
|
||||||
field.add_element(std::min(
|
|
||||||
speed_kmh_idx, 127u)); // save the speed value, capped at 127
|
|
||||||
field.add_element(1); // "is_small" tag key offset
|
|
||||||
field.add_element(
|
|
||||||
128 + (component_id.is_tiny ? 0 : 1)); // is_small feature offset
|
|
||||||
field.add_element(2); // "datasource" tag key offset
|
|
||||||
field.add_element(130 + datasource_idx); // datasource value offset
|
|
||||||
field.add_element(3); // "weight" tag key offset
|
|
||||||
field.add_element(130 + max_datasource_id + 1 +
|
|
||||||
weight_idx); // weight value offset
|
|
||||||
field.add_element(4); // "duration" tag key offset
|
|
||||||
field.add_element(130 + max_datasource_id + 1 +
|
|
||||||
duration_idx); // duration value offset
|
|
||||||
field.add_element(5); // "name" tag key offset
|
|
||||||
|
|
||||||
field.add_element(130 + max_datasource_id + 1 +
|
|
||||||
line_int_index.values().size() + name_idx);
|
|
||||||
|
|
||||||
field.add_element(6); // rate tag key offset
|
|
||||||
field.add_element(130 + max_datasource_id + 1 + rate_idx);
|
|
||||||
}
|
|
||||||
{
|
|
||||||
|
|
||||||
// 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);
|
|
||||||
}
|
|
||||||
};
|
|
||||||
|
|
||||||
// If this is a valid forward edge, go ahead and add it to the tile
|
// If this is a valid forward edge, go ahead and add it to the tile
|
||||||
if (forward_duration != 0 && edge.forward_segment_id.enabled)
|
if (forward_duration != 0 && edge.forward_segment_id.enabled)
|
||||||
{
|
{
|
||||||
std::int32_t start_x = 0;
|
|
||||||
std::int32_t start_y = 0;
|
|
||||||
|
|
||||||
// Calculate the speed for this line
|
// Calculate the speed for this line
|
||||||
// Speeds are looked up in a simple 1:1 table, so the speed value == lookup
|
|
||||||
// table index
|
|
||||||
std::uint32_t speed_kmh_idx =
|
std::uint32_t speed_kmh_idx =
|
||||||
static_cast<std::uint32_t>(round(length / forward_duration * 10 * 3.6));
|
static_cast<std::uint32_t>(round(length / forward_duration * 10 * 3.6));
|
||||||
|
|
||||||
@@ -616,15 +505,19 @@ void encodeVectorTile(const DataFacadeBase &facade,
|
|||||||
auto tile_line = coordinatesToTileLine(a, b, tile_bbox);
|
auto tile_line = coordinatesToTileLine(a, b, tile_bbox);
|
||||||
if (!tile_line.empty())
|
if (!tile_line.empty())
|
||||||
{
|
{
|
||||||
encode_tile_line(tile_line,
|
SpeedLayerFeatureBuilder fbuilder{speeds_layer, id};
|
||||||
speed_kmh_idx,
|
fbuilder.add_linestring_from_container(tile_line);
|
||||||
line_int_index.indexOf(forward_rate),
|
|
||||||
line_int_index.indexOf(forward_weight),
|
fbuilder.set_speed(speed_kmh_idx);
|
||||||
line_int_index.indexOf(forward_duration),
|
fbuilder.set_is_small(component_id.is_tiny);
|
||||||
forward_datasource_idx,
|
fbuilder.set_datasource(
|
||||||
line_string_index.indexOf(name),
|
facade.GetDatasourceName(forward_datasource_idx).to_string());
|
||||||
start_x,
|
fbuilder.set_weight(forward_weight / 10.0);
|
||||||
start_y);
|
fbuilder.set_duration(forward_duration / 10.0);
|
||||||
|
fbuilder.set_name(name);
|
||||||
|
fbuilder.set_rate(forward_rate / 10.0);
|
||||||
|
|
||||||
|
fbuilder.commit();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -632,12 +525,7 @@ void encodeVectorTile(const DataFacadeBase &facade,
|
|||||||
// properties
|
// properties
|
||||||
if (reverse_duration != 0 && edge.reverse_segment_id.enabled)
|
if (reverse_duration != 0 && edge.reverse_segment_id.enabled)
|
||||||
{
|
{
|
||||||
std::int32_t start_x = 0;
|
|
||||||
std::int32_t start_y = 0;
|
|
||||||
|
|
||||||
// Calculate the speed for this line
|
// Calculate the speed for this line
|
||||||
// Speeds are looked up in a simple 1:1 table, so the speed value == lookup
|
|
||||||
// table index
|
|
||||||
std::uint32_t speed_kmh_idx =
|
std::uint32_t speed_kmh_idx =
|
||||||
static_cast<std::uint32_t>(round(length / reverse_duration * 10 * 3.6));
|
static_cast<std::uint32_t>(round(length / reverse_duration * 10 * 3.6));
|
||||||
|
|
||||||
@@ -650,232 +538,52 @@ void encodeVectorTile(const DataFacadeBase &facade,
|
|||||||
auto tile_line = coordinatesToTileLine(b, a, tile_bbox);
|
auto tile_line = coordinatesToTileLine(b, a, tile_bbox);
|
||||||
if (!tile_line.empty())
|
if (!tile_line.empty())
|
||||||
{
|
{
|
||||||
encode_tile_line(tile_line,
|
SpeedLayerFeatureBuilder fbuilder{speeds_layer, id};
|
||||||
speed_kmh_idx,
|
fbuilder.add_linestring_from_container(tile_line);
|
||||||
line_int_index.indexOf(reverse_rate),
|
|
||||||
line_int_index.indexOf(reverse_weight),
|
fbuilder.set_speed(speed_kmh_idx);
|
||||||
line_int_index.indexOf(reverse_duration),
|
fbuilder.set_is_small(component_id.is_tiny);
|
||||||
reverse_datasource_idx,
|
fbuilder.set_datasource(
|
||||||
line_string_index.indexOf(name),
|
facade.GetDatasourceName(reverse_datasource_idx).to_string());
|
||||||
start_x,
|
fbuilder.set_weight(reverse_weight / 10.0);
|
||||||
start_y);
|
fbuilder.set_duration(reverse_duration / 10.0);
|
||||||
|
fbuilder.set_name(name);
|
||||||
|
fbuilder.set_rate(reverse_rate / 10.0);
|
||||||
|
|
||||||
|
fbuilder.commit();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// Field id 3 is the "keys" attribute
|
|
||||||
// We need two "key" fields, these are referred to with 0 and 1 (their array
|
|
||||||
// indexes) earlier
|
|
||||||
line_layer_writer.add_string(util::vector_tile::KEY_TAG, "speed");
|
|
||||||
line_layer_writer.add_string(util::vector_tile::KEY_TAG, "is_small");
|
|
||||||
line_layer_writer.add_string(util::vector_tile::KEY_TAG, "datasource");
|
|
||||||
line_layer_writer.add_string(util::vector_tile::KEY_TAG, "weight");
|
|
||||||
line_layer_writer.add_string(util::vector_tile::KEY_TAG, "duration");
|
|
||||||
line_layer_writer.add_string(util::vector_tile::KEY_TAG, "name");
|
|
||||||
line_layer_writer.add_string(util::vector_tile::KEY_TAG, "rate");
|
|
||||||
|
|
||||||
// Now, we write out the possible speed value arrays and possible is_tiny
|
|
||||||
// values. Field type 4 is the "values" field. It's a variable type field,
|
|
||||||
// so requires a two-step write (create the field, then write its value)
|
|
||||||
for (std::size_t i = 0; i < 128; i++)
|
|
||||||
{
|
|
||||||
// Writing field type 4 == variant type
|
|
||||||
protozero::pbf_writer values_writer(line_layer_writer,
|
|
||||||
util::vector_tile::VARIANT_TAG);
|
|
||||||
// Attribute value 5 == uint64 type
|
|
||||||
values_writer.add_uint64(util::vector_tile::VARIANT_TYPE_UINT64, i);
|
|
||||||
}
|
|
||||||
{
|
|
||||||
protozero::pbf_writer values_writer(line_layer_writer,
|
|
||||||
util::vector_tile::VARIANT_TAG);
|
|
||||||
// Attribute value 7 == bool type
|
|
||||||
values_writer.add_bool(util::vector_tile::VARIANT_TYPE_BOOL, true);
|
|
||||||
}
|
|
||||||
{
|
|
||||||
protozero::pbf_writer values_writer(line_layer_writer,
|
|
||||||
util::vector_tile::VARIANT_TAG);
|
|
||||||
// Attribute value 7 == bool type
|
|
||||||
values_writer.add_bool(util::vector_tile::VARIANT_TYPE_BOOL, false);
|
|
||||||
}
|
|
||||||
for (std::size_t i = 0; i <= max_datasource_id; i++)
|
|
||||||
{
|
|
||||||
// Writing field type 4 == variant type
|
|
||||||
protozero::pbf_writer values_writer(line_layer_writer,
|
|
||||||
util::vector_tile::VARIANT_TAG);
|
|
||||||
// Attribute value 1 == string type
|
|
||||||
values_writer.add_string(util::vector_tile::VARIANT_TYPE_STRING,
|
|
||||||
facade.GetDatasourceName(i).to_string());
|
|
||||||
}
|
|
||||||
for (auto value : line_int_index.values())
|
|
||||||
{
|
|
||||||
// Writing field type 4 == variant type
|
|
||||||
protozero::pbf_writer values_writer(line_layer_writer,
|
|
||||||
util::vector_tile::VARIANT_TAG);
|
|
||||||
// Attribute value 2 == float type
|
|
||||||
// Durations come out of OSRM in integer deciseconds, so we convert them
|
|
||||||
// to seconds with a simple /10 for display
|
|
||||||
values_writer.add_double(util::vector_tile::VARIANT_TYPE_DOUBLE, value / 10.);
|
|
||||||
}
|
|
||||||
|
|
||||||
for (const auto &name : line_string_index.values())
|
|
||||||
{
|
|
||||||
// Writing field type 4 == variant type
|
|
||||||
protozero::pbf_writer values_writer(line_layer_writer,
|
|
||||||
util::vector_tile::VARIANT_TAG);
|
|
||||||
// Attribute value 1 == string type
|
|
||||||
values_writer.add_string(
|
|
||||||
util::vector_tile::VARIANT_TYPE_STRING, name.data(), name.size());
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// Only add the turn layer to the tile if it has some features (we sometimes won't
|
// Only add the turn layer to the tile if it has some features (we sometimes won't
|
||||||
// for tiles of z<16, and tiles that don't show any intersections)
|
// for tiles of z<16, and tiles that don't show any intersections)
|
||||||
if (!all_turn_data.empty())
|
if (!all_turn_data.empty())
|
||||||
{
|
{
|
||||||
|
TurnsLayer turns_layer{tile};
|
||||||
struct EncodedTurnData
|
uint64_t id = 0;
|
||||||
|
for (const auto &turn_data : all_turn_data)
|
||||||
{
|
{
|
||||||
util::Coordinate coordinate;
|
const auto tile_point = coordinatesToTilePoint(turn_data.coordinate, tile_bbox);
|
||||||
std::size_t angle_index;
|
if (boost::geometry::within(point_t(tile_point.x, tile_point.y), clip_box))
|
||||||
std::size_t turn_index;
|
|
||||||
std::size_t duration_index;
|
|
||||||
std::size_t weight_index;
|
|
||||||
std::size_t turntype_index;
|
|
||||||
std::size_t turnmodifier_index;
|
|
||||||
};
|
|
||||||
// we need to pre-encode all values here because we need the full offsets later
|
|
||||||
// for encoding the actual features.
|
|
||||||
std::vector<EncodedTurnData> encoded_turn_data(all_turn_data.size());
|
|
||||||
std::transform(
|
|
||||||
all_turn_data.begin(),
|
|
||||||
all_turn_data.end(),
|
|
||||||
encoded_turn_data.begin(),
|
|
||||||
[&](const routing_algorithms::TurnData &t) {
|
|
||||||
auto angle_idx = point_int_index.add(t.in_angle);
|
|
||||||
auto turn_idx = point_int_index.add(t.turn_angle);
|
|
||||||
auto duration_idx =
|
|
||||||
point_float_index.add(t.duration / 10.0); // Note conversion to float here
|
|
||||||
auto weight_idx =
|
|
||||||
point_float_index.add(t.weight / 10.0); // Note conversion to float here
|
|
||||||
|
|
||||||
auto turntype_idx = point_string_index.add(
|
|
||||||
osrm::guidance::internalInstructionTypeToString(t.turn_instruction.type));
|
|
||||||
auto turnmodifier_idx =
|
|
||||||
point_string_index.add(osrm::guidance::instructionModifierToString(
|
|
||||||
t.turn_instruction.direction_modifier));
|
|
||||||
return EncodedTurnData{t.coordinate,
|
|
||||||
angle_idx,
|
|
||||||
turn_idx,
|
|
||||||
duration_idx,
|
|
||||||
weight_idx,
|
|
||||||
turntype_idx,
|
|
||||||
turnmodifier_idx};
|
|
||||||
});
|
|
||||||
|
|
||||||
// Now write the points layer for turn penalty data:
|
|
||||||
// Add a layer object to the PBF stream. 3=='layer' from the vector tile spec
|
|
||||||
// (2.1)
|
|
||||||
protozero::pbf_writer point_layer_writer(tile_writer, util::vector_tile::LAYER_TAG);
|
|
||||||
point_layer_writer.add_uint32(util::vector_tile::VERSION_TAG, 2); // version
|
|
||||||
point_layer_writer.add_string(util::vector_tile::NAME_TAG, "turns"); // name
|
|
||||||
point_layer_writer.add_uint32(util::vector_tile::EXTENT_TAG,
|
|
||||||
util::vector_tile::EXTENT); // extent
|
|
||||||
|
|
||||||
// Begin writing the set of point features
|
|
||||||
{
|
|
||||||
// Start each features with an ID starting at 1
|
|
||||||
int id = 1;
|
|
||||||
|
|
||||||
// Helper function to encode a new point feature on a vector tile.
|
|
||||||
const auto encode_tile_point = [&](const FixedPoint &tile_point,
|
|
||||||
const auto &point_turn_data) {
|
|
||||||
protozero::pbf_writer feature_writer(point_layer_writer,
|
|
||||||
util::vector_tile::FEATURE_TAG);
|
|
||||||
// Field 3 is the "geometry type" field. Value 1 is "point"
|
|
||||||
feature_writer.add_enum(
|
|
||||||
util::vector_tile::GEOMETRY_TAG,
|
|
||||||
util::vector_tile::GEOMETRY_TYPE_POINT); // geometry type
|
|
||||||
feature_writer.add_uint64(util::vector_tile::ID_TAG, id++); // id
|
|
||||||
{
|
|
||||||
// Write out the 4 properties we want on the feature. These
|
|
||||||
// refer to indexes in the properties lookup table, which we
|
|
||||||
// add to the tile after we add all features.
|
|
||||||
protozero::packed_field_uint32 field(
|
|
||||||
feature_writer, util::vector_tile::FEATURE_ATTRIBUTES_TAG);
|
|
||||||
field.add_element(0); // "bearing_in" tag key offset
|
|
||||||
field.add_element(point_turn_data.angle_index);
|
|
||||||
field.add_element(1); // "turn_angle" tag key offset
|
|
||||||
field.add_element(point_turn_data.turn_index);
|
|
||||||
field.add_element(2); // "cost" tag key offset
|
|
||||||
field.add_element(point_int_index.size() + point_turn_data.duration_index);
|
|
||||||
field.add_element(3); // "weight" tag key offset
|
|
||||||
field.add_element(point_int_index.size() + point_turn_data.weight_index);
|
|
||||||
field.add_element(4); // "type" tag key offset
|
|
||||||
field.add_element(point_int_index.size() + point_float_index.size() +
|
|
||||||
point_turn_data.turntype_index);
|
|
||||||
field.add_element(5); // "modifier" tag key offset
|
|
||||||
field.add_element(point_int_index.size() + point_float_index.size() +
|
|
||||||
point_turn_data.turnmodifier_index);
|
|
||||||
}
|
|
||||||
{
|
|
||||||
// Add the geometry as the last field in this feature
|
|
||||||
protozero::packed_field_uint32 geometry(
|
|
||||||
feature_writer, util::vector_tile::FEATURE_GEOMETRIES_TAG);
|
|
||||||
encodePoint(tile_point, geometry);
|
|
||||||
}
|
|
||||||
};
|
|
||||||
|
|
||||||
// Loop over all the turns we found and add them as features to the layer
|
|
||||||
for (const auto &turndata : encoded_turn_data)
|
|
||||||
{
|
{
|
||||||
const auto tile_point = coordinatesToTilePoint(turndata.coordinate, tile_bbox);
|
TurnsLayerFeatureBuilder fbuilder{turns_layer, ++id};
|
||||||
if (!boost::geometry::within(point_t(tile_point.x, tile_point.y), clip_box))
|
fbuilder.add_point(tile_point);
|
||||||
{
|
|
||||||
continue;
|
fbuilder.set_bearing_in(turn_data.in_angle);
|
||||||
}
|
fbuilder.set_turn_angle(turn_data.turn_angle);
|
||||||
encode_tile_point(tile_point, turndata);
|
fbuilder.set_cost(turn_data.duration / 10.0);
|
||||||
|
fbuilder.set_weight(turn_data.weight / 10.0);
|
||||||
|
fbuilder.set_turn(turn_data.turn_instruction);
|
||||||
|
|
||||||
|
fbuilder.commit();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// Add the names of the three attributes we added to all the turn penalty
|
|
||||||
// features previously. The indexes used there refer to these keys.
|
|
||||||
point_layer_writer.add_string(util::vector_tile::KEY_TAG, "bearing_in");
|
|
||||||
point_layer_writer.add_string(util::vector_tile::KEY_TAG, "turn_angle");
|
|
||||||
point_layer_writer.add_string(util::vector_tile::KEY_TAG, "cost");
|
|
||||||
point_layer_writer.add_string(util::vector_tile::KEY_TAG, "weight");
|
|
||||||
point_layer_writer.add_string(util::vector_tile::KEY_TAG, "type");
|
|
||||||
point_layer_writer.add_string(util::vector_tile::KEY_TAG, "modifier");
|
|
||||||
|
|
||||||
// Now, save the lists of integers and floats that our features refer to.
|
|
||||||
for (const auto &value : point_int_index.values())
|
|
||||||
{
|
|
||||||
protozero::pbf_writer values_writer(point_layer_writer,
|
|
||||||
util::vector_tile::VARIANT_TAG);
|
|
||||||
values_writer.add_sint64(util::vector_tile::VARIANT_TYPE_SINT64, value);
|
|
||||||
}
|
|
||||||
for (const auto &value : point_float_index.values())
|
|
||||||
{
|
|
||||||
protozero::pbf_writer values_writer(point_layer_writer,
|
|
||||||
util::vector_tile::VARIANT_TAG);
|
|
||||||
values_writer.add_float(util::vector_tile::VARIANT_TYPE_FLOAT, value);
|
|
||||||
}
|
|
||||||
for (const auto &value : point_string_index.values())
|
|
||||||
{
|
|
||||||
protozero::pbf_writer values_writer(point_layer_writer,
|
|
||||||
util::vector_tile::VARIANT_TAG);
|
|
||||||
values_writer.add_string(util::vector_tile::VARIANT_TYPE_STRING, value);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// OSM Node tile layer
|
// OSM Node tile layer
|
||||||
{
|
{
|
||||||
protozero::pbf_writer point_layer_writer(tile_writer, util::vector_tile::LAYER_TAG);
|
|
||||||
point_layer_writer.add_uint32(util::vector_tile::VERSION_TAG, 2); // version
|
|
||||||
point_layer_writer.add_string(util::vector_tile::NAME_TAG, "osmnodes"); // name
|
|
||||||
point_layer_writer.add_uint32(util::vector_tile::EXTENT_TAG,
|
|
||||||
util::vector_tile::EXTENT); // extent
|
|
||||||
|
|
||||||
std::vector<NodeID> internal_nodes;
|
std::vector<NodeID> internal_nodes;
|
||||||
internal_nodes.reserve(edges.size() * 2);
|
internal_nodes.reserve(edges.size() * 2);
|
||||||
for (const auto &edge : edges)
|
for (const auto &edge : edges)
|
||||||
@@ -887,6 +595,8 @@ void encodeVectorTile(const DataFacadeBase &facade,
|
|||||||
auto new_end = std::unique(internal_nodes.begin(), internal_nodes.end());
|
auto new_end = std::unique(internal_nodes.begin(), internal_nodes.end());
|
||||||
internal_nodes.resize(new_end - internal_nodes.begin());
|
internal_nodes.resize(new_end - internal_nodes.begin());
|
||||||
|
|
||||||
|
vtzero::layer_builder osmnodes_layer{tile, "osmnodes"};
|
||||||
|
|
||||||
for (const auto &internal_node : internal_nodes)
|
for (const auto &internal_node : internal_nodes)
|
||||||
{
|
{
|
||||||
const auto coord = facade.GetCoordinateOfNode(internal_node);
|
const auto coord = facade.GetCoordinateOfNode(internal_node);
|
||||||
@@ -895,32 +605,19 @@ void encodeVectorTile(const DataFacadeBase &facade,
|
|||||||
{
|
{
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
protozero::pbf_writer feature_writer(point_layer_writer,
|
|
||||||
util::vector_tile::FEATURE_TAG);
|
vtzero::point_feature_builder fbuilder{osmnodes_layer};
|
||||||
// Field 3 is the "geometry type" field. Value 1 is "point"
|
fbuilder.set_id(
|
||||||
feature_writer.add_enum(util::vector_tile::GEOMETRY_TAG,
|
static_cast<OSMNodeID::value_type>(facade.GetOSMNodeIDOfNode(internal_node)));
|
||||||
util::vector_tile::GEOMETRY_TYPE_POINT); // geometry type
|
fbuilder.add_point(tile_point);
|
||||||
const auto osmid =
|
fbuilder.commit();
|
||||||
static_cast<OSMNodeID::value_type>(facade.GetOSMNodeIDOfNode(internal_node));
|
|
||||||
feature_writer.add_uint64(util::vector_tile::ID_TAG, osmid); // id
|
|
||||||
// There are no additional properties, just the ID and the geometry
|
|
||||||
{
|
|
||||||
// Add the geometry as the last field in this feature
|
|
||||||
protozero::packed_field_uint32 geometry(
|
|
||||||
feature_writer, util::vector_tile::FEATURE_GEOMETRIES_TAG);
|
|
||||||
encodePoint(tile_point, geometry);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Internal nodes tile layer
|
||||||
{
|
{
|
||||||
protozero::pbf_writer line_layer_writer(tile_writer, util::vector_tile::LAYER_TAG);
|
vtzero::layer_builder internal_nodes_layer{tile, "internal-nodes"};
|
||||||
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)
|
for (auto edgeNodeID : segregated_nodes)
|
||||||
{
|
{
|
||||||
auto const geomIndex = facade.GetGeometryIndex(edgeNodeID);
|
auto const geomIndex = facade.GetGeometryIndex(edgeNodeID);
|
||||||
@@ -937,46 +634,21 @@ void encodeVectorTile(const DataFacadeBase &facade,
|
|||||||
points.push_back(facade.GetCoordinateOfNode(nodeID));
|
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);
|
auto tile_lines = coordinatesToTileLine(points, tile_bbox);
|
||||||
if (!tile_lines.empty())
|
if (!tile_lines.empty())
|
||||||
{
|
{
|
||||||
for (auto const &tl : tile_lines)
|
vtzero::linestring_feature_builder fbuilder{internal_nodes_layer};
|
||||||
|
for (auto const &tile_line : tile_lines)
|
||||||
{
|
{
|
||||||
encode_tile_line(tl, start_x, start_y);
|
fbuilder.add_linestring_from_container(tile_line);
|
||||||
}
|
}
|
||||||
|
fbuilder.commit();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
// protozero serializes data during object destructors, so once the scope closes,
|
|
||||||
// our result buffer will have all the tile data encoded into it.
|
tile.serialize(pbf_buffer);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
+24
-19
@@ -131,7 +131,7 @@ void ManipulateTableForFSE(const std::size_t source_id,
|
|||||||
result_table.SetValue(destination_id, i, INVALID_EDGE_WEIGHT);
|
result_table.SetValue(destination_id, i, INVALID_EDGE_WEIGHT);
|
||||||
}
|
}
|
||||||
|
|
||||||
// set destination->source to zero so rountrip treats source and
|
// set destination->source to zero so roundtrip treats source and
|
||||||
// destination as one location
|
// destination as one location
|
||||||
result_table.SetValue(destination_id, source_id, 0);
|
result_table.SetValue(destination_id, source_id, 0);
|
||||||
|
|
||||||
@@ -216,61 +216,66 @@ Status TripPlugin::HandleRequest(const RoutingAlgorithmsInterface &algorithms,
|
|||||||
BOOST_ASSERT(snapped_phantoms.size() == number_of_locations);
|
BOOST_ASSERT(snapped_phantoms.size() == number_of_locations);
|
||||||
|
|
||||||
// compute the duration table of all phantom nodes
|
// compute the duration table of all phantom nodes
|
||||||
auto result_table = util::DistTableWrapper<EdgeWeight>(
|
auto result_duration_table = util::DistTableWrapper<EdgeWeight>(
|
||||||
algorithms.ManyToManySearch(snapped_phantoms, {}, {}), number_of_locations);
|
algorithms
|
||||||
|
.ManyToManySearch(
|
||||||
|
snapped_phantoms, {}, {}, /*requestDistance*/ false, /*requestDuration*/ true)
|
||||||
|
.first,
|
||||||
|
number_of_locations);
|
||||||
|
|
||||||
if (result_table.size() == 0)
|
if (result_duration_table.size() == 0)
|
||||||
{
|
{
|
||||||
return Status::Error;
|
return Status::Error;
|
||||||
}
|
}
|
||||||
|
|
||||||
const constexpr std::size_t BF_MAX_FEASABLE = 10;
|
const constexpr std::size_t BF_MAX_FEASABLE = 10;
|
||||||
BOOST_ASSERT_MSG(result_table.size() == number_of_locations * number_of_locations,
|
BOOST_ASSERT_MSG(result_duration_table.size() == number_of_locations * number_of_locations,
|
||||||
"Distance Table has wrong size");
|
"Distance Table has wrong size");
|
||||||
|
|
||||||
if (!IsStronglyConnectedComponent(result_table))
|
if (!IsStronglyConnectedComponent(result_duration_table))
|
||||||
{
|
{
|
||||||
return Error("NoTrips", "No trip visiting all destinations possible.", json_result);
|
return Error("NoTrips", "No trip visiting all destinations possible.", json_result);
|
||||||
}
|
}
|
||||||
|
|
||||||
if (fixed_start && fixed_end)
|
if (fixed_start && fixed_end)
|
||||||
{
|
{
|
||||||
ManipulateTableForFSE(source_id, destination_id, result_table);
|
ManipulateTableForFSE(source_id, destination_id, result_duration_table);
|
||||||
}
|
}
|
||||||
|
|
||||||
std::vector<NodeID> trip;
|
std::vector<NodeID> duration_trip;
|
||||||
trip.reserve(number_of_locations);
|
duration_trip.reserve(number_of_locations);
|
||||||
// get an optimized order in which the destinations should be visited
|
// get an optimized order in which the destinations should be visited
|
||||||
if (number_of_locations < BF_MAX_FEASABLE)
|
if (number_of_locations < BF_MAX_FEASABLE)
|
||||||
{
|
{
|
||||||
trip = trip::BruteForceTrip(number_of_locations, result_table);
|
duration_trip = trip::BruteForceTrip(number_of_locations, result_duration_table);
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
trip = trip::FarthestInsertionTrip(number_of_locations, result_table);
|
duration_trip = trip::FarthestInsertionTrip(number_of_locations, result_duration_table);
|
||||||
}
|
}
|
||||||
|
|
||||||
// rotate result such that roundtrip starts at node with index 0
|
// rotate result such that roundtrip starts at node with index 0
|
||||||
// thist first if covers scenarios: !fixed_end || fixed_start || (fixed_start && fixed_end)
|
// thist first if covers scenarios: !fixed_end || fixed_start || (fixed_start && fixed_end)
|
||||||
if (!fixed_end || fixed_start)
|
if (!fixed_end || fixed_start)
|
||||||
{
|
{
|
||||||
auto desired_start_index = std::find(std::begin(trip), std::end(trip), 0);
|
auto desired_start_index = std::find(std::begin(duration_trip), std::end(duration_trip), 0);
|
||||||
BOOST_ASSERT(desired_start_index != std::end(trip));
|
BOOST_ASSERT(desired_start_index != std::end(duration_trip));
|
||||||
std::rotate(std::begin(trip), desired_start_index, std::end(trip));
|
std::rotate(std::begin(duration_trip), desired_start_index, std::end(duration_trip));
|
||||||
}
|
}
|
||||||
else if (fixed_end && !fixed_start && parameters.roundtrip)
|
else if (fixed_end && !fixed_start && parameters.roundtrip)
|
||||||
{
|
{
|
||||||
auto desired_start_index = std::find(std::begin(trip), std::end(trip), destination_id);
|
auto desired_start_index =
|
||||||
BOOST_ASSERT(desired_start_index != std::end(trip));
|
std::find(std::begin(duration_trip), std::end(duration_trip), destination_id);
|
||||||
std::rotate(std::begin(trip), desired_start_index, std::end(trip));
|
BOOST_ASSERT(desired_start_index != std::end(duration_trip));
|
||||||
|
std::rotate(std::begin(duration_trip), desired_start_index, std::end(duration_trip));
|
||||||
}
|
}
|
||||||
|
|
||||||
// get the route when visiting all destinations in optimized order
|
// get the route when visiting all destinations in optimized order
|
||||||
InternalRouteResult route =
|
InternalRouteResult route =
|
||||||
ComputeRoute(algorithms, snapped_phantoms, trip, parameters.roundtrip);
|
ComputeRoute(algorithms, snapped_phantoms, duration_trip, parameters.roundtrip);
|
||||||
|
|
||||||
// get api response
|
// get api response
|
||||||
const std::vector<std::vector<NodeID>> trips = {trip};
|
const std::vector<std::vector<NodeID>> trips = {duration_trip};
|
||||||
const std::vector<InternalRouteResult> routes = {route};
|
const std::vector<InternalRouteResult> routes = {route};
|
||||||
api::TripAPI trip_api{facade, parameters};
|
api::TripAPI trip_api{facade, parameters};
|
||||||
trip_api.MakeResponse(trips, routes, snapped_phantoms, json_result);
|
trip_api.MakeResponse(trips, routes, snapped_phantoms, json_result);
|
||||||
|
|||||||
@@ -90,7 +90,7 @@ void alternativeRoutingStep(const DataFacade<Algorithm> &facade,
|
|||||||
else
|
else
|
||||||
{
|
{
|
||||||
// check whether there is a loop present at the node
|
// check whether there is a loop present at the node
|
||||||
const auto loop_weight = getLoopWeight<false>(facade, node);
|
const auto loop_weight = std::get<0>(getLoopWeight<false>(facade, node));
|
||||||
const EdgeWeight new_weight_with_loop = new_weight + loop_weight;
|
const EdgeWeight new_weight_with_loop = new_weight + loop_weight;
|
||||||
if (loop_weight != INVALID_EDGE_WEIGHT &&
|
if (loop_weight != INVALID_EDGE_WEIGHT &&
|
||||||
new_weight_with_loop <= *upper_bound_to_shortest_path_weight)
|
new_weight_with_loop <= *upper_bound_to_shortest_path_weight)
|
||||||
@@ -558,7 +558,7 @@ bool viaNodeCandidatePassesTTest(SearchEngineData<Algorithm> &engine_working_dat
|
|||||||
}
|
}
|
||||||
return (upper_bound <= t_test_path_weight);
|
return (upper_bound <= t_test_path_weight);
|
||||||
}
|
}
|
||||||
} // anon. namespace
|
} // namespace
|
||||||
|
|
||||||
InternalManyRoutesResult alternativePathSearch(SearchEngineData<Algorithm> &engine_working_data,
|
InternalManyRoutesResult alternativePathSearch(SearchEngineData<Algorithm> &engine_working_data,
|
||||||
const DataFacade<Algorithm> &facade,
|
const DataFacade<Algorithm> &facade,
|
||||||
@@ -853,4 +853,4 @@ InternalManyRoutesResult alternativePathSearch(SearchEngineData<Algorithm> &engi
|
|||||||
|
|
||||||
} // namespace routing_algorithms
|
} // namespace routing_algorithms
|
||||||
} // namespace engine
|
} // namespace engine
|
||||||
} // namespace osrm}
|
} // namespace osrm
|
||||||
|
|||||||
@@ -34,22 +34,27 @@ using Facade = DataFacade<Algorithm>;
|
|||||||
namespace
|
namespace
|
||||||
{
|
{
|
||||||
|
|
||||||
// Alternative paths candidate via nodes are taken from overlapping search spaces.
|
struct Parameters
|
||||||
// Overlapping by a third guarantees us taking candidate nodes "from the middle".
|
{
|
||||||
const constexpr auto kSearchSpaceOverlapFactor = 1.33;
|
// Alternative paths candidate via nodes are taken from overlapping search spaces.
|
||||||
// Unpack n-times more candidate paths to run high-quality checks on.
|
// Overlapping by a third guarantees us taking candidate nodes "from the middle".
|
||||||
// Unpacking paths yields higher chance to find good alternatives but is also expensive.
|
double kSearchSpaceOverlapFactor = 1.33;
|
||||||
const constexpr auto kAlternativesToUnpackFactor = 2.0;
|
// Unpack n-times more candidate paths to run high-quality checks on.
|
||||||
// Alternative paths length requirement (stretch).
|
// Unpacking paths yields higher chance to find good alternatives but is also expensive.
|
||||||
// At most 25% longer then the shortest path.
|
unsigned kAlternativesToUnpackFactor = 2;
|
||||||
const constexpr auto kAtMostLongerBy = 0.25;
|
// Alternative paths length requirement (stretch).
|
||||||
// Alternative paths similarity requirement (sharing).
|
// At most 25% longer then the shortest path.
|
||||||
// At least 15% different than the shortest path.
|
double kAtMostLongerBy = 0.25;
|
||||||
const constexpr auto kAtLeastDifferentBy = 0.85;
|
// Alternative paths similarity requirement (sharing).
|
||||||
// Alternative paths are still reasonable around the via node candidate (local optimality).
|
// At least 25% different than the shortest path.
|
||||||
// At least optimal around 10% sub-paths around the via node candidate.
|
double kAtMostSameBy = 0.75;
|
||||||
const /*constexpr*/ auto kAtLeastOptimalAroundViaBy = 0.10;
|
// Alternative paths are still reasonable around the via node candidate (local optimality).
|
||||||
// gcc 7.1 ICE ^
|
// At least optimal around 10% sub-paths around the via node candidate.
|
||||||
|
double kAtLeastOptimalAroundViaBy = 0.1;
|
||||||
|
// Alternative paths similarity requirement (sharing) based on calles.
|
||||||
|
// At least 15% different than the shortest path.
|
||||||
|
double kCellsAtMostSameBy = 0.95;
|
||||||
|
};
|
||||||
|
|
||||||
// Represents a via middle node where forward (from s) and backward (from t)
|
// Represents a via middle node where forward (from s) and backward (from t)
|
||||||
// search spaces overlap and the weight a path (made up of s,via and via,t) has.
|
// search spaces overlap and the weight a path (made up of s,via and via,t) has.
|
||||||
@@ -71,11 +76,104 @@ struct WeightedViaNodePackedPath
|
|||||||
// its total weight and the via node used to construct the path.
|
// its total weight and the via node used to construct the path.
|
||||||
struct WeightedViaNodeUnpackedPath
|
struct WeightedViaNodeUnpackedPath
|
||||||
{
|
{
|
||||||
|
double sharing;
|
||||||
WeightedViaNode via;
|
WeightedViaNode via;
|
||||||
UnpackedNodes nodes;
|
UnpackedNodes nodes;
|
||||||
UnpackedEdges edges;
|
UnpackedEdges edges;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
// Scale the maximum allowed weight increase based on its magnitude:
|
||||||
|
// - Shortest path 10 minutes, alternative 13 minutes => Factor of 0.30 ok
|
||||||
|
// - Shortest path 10 hours, alternative 13 hours => Factor of 0.30 unreasonable
|
||||||
|
double getLongerByFactorBasedOnDuration(const EdgeWeight duration)
|
||||||
|
{
|
||||||
|
BOOST_ASSERT(duration != INVALID_EDGE_WEIGHT);
|
||||||
|
|
||||||
|
// We only have generic weights here and no durations without unpacking.
|
||||||
|
// We also have restricted way penalties which are huge and will screw scaling here.
|
||||||
|
//
|
||||||
|
// Users can pass us generic weights not based on durations; we can't do anything about
|
||||||
|
// it here other than either generating too many or no alternatives in these cases.
|
||||||
|
//
|
||||||
|
// We scale the weights with a step function based on some rough guestimates, so that
|
||||||
|
// they match tens of minutes, in the low hours, tens of hours, etc.
|
||||||
|
|
||||||
|
// Computed using a least-squares curve fitiing on the following values:
|
||||||
|
//
|
||||||
|
// def func(xs, a, b, c, d):
|
||||||
|
// return a + b/(xs-d) + c/(xs-d)**3
|
||||||
|
//
|
||||||
|
// xs = np.array([5 * 60, 10 * 60, 30 * 60, 60 * 60, 3 * 60 * 60, 10 * 60 * 60])
|
||||||
|
// ys = np.array([1.0, 0.75, 0.5, 0.4, 0.3, 0.2])
|
||||||
|
//
|
||||||
|
// xs_interp = np.arange(5*60, 10*60*60, 5*60)
|
||||||
|
// ys_interp = np.interp(xs_interp, xs, ys)
|
||||||
|
//
|
||||||
|
// params, _ = scipy.optimize.curve_fit(func, xs_interp, ys_interp)
|
||||||
|
//
|
||||||
|
// The hyperbolic shape was chosen because it interpolated well between
|
||||||
|
// the given datapoints and drops off for large durations.
|
||||||
|
const constexpr auto a = 1.91578463e-01;
|
||||||
|
const constexpr auto b = 1.35118442e+03;
|
||||||
|
const constexpr auto c = 2.45437877e+09;
|
||||||
|
const constexpr auto d = -2.07944571e+03;
|
||||||
|
|
||||||
|
if (duration < EdgeWeight(5 * 60))
|
||||||
|
{
|
||||||
|
return 1.0;
|
||||||
|
}
|
||||||
|
else if (duration > EdgeWeight(10 * 60 * 60))
|
||||||
|
{
|
||||||
|
return 0.20;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Bigger than 10 minutes but smaller than 10 hours
|
||||||
|
BOOST_ASSERT(duration >= 5 * 60 && duration <= 10 * 60 * 60);
|
||||||
|
|
||||||
|
return a + b / (duration - d) + c / std::pow(duration - d, 3);
|
||||||
|
}
|
||||||
|
|
||||||
|
Parameters parametersFromRequest(const PhantomNodes &phantom_node_pair)
|
||||||
|
{
|
||||||
|
Parameters parameters;
|
||||||
|
|
||||||
|
const auto distance = util::coordinate_calculation::haversineDistance(
|
||||||
|
phantom_node_pair.source_phantom.location, phantom_node_pair.target_phantom.location);
|
||||||
|
|
||||||
|
// 10km
|
||||||
|
if (distance < 10000.)
|
||||||
|
{
|
||||||
|
parameters.kAlternativesToUnpackFactor = 10.0;
|
||||||
|
parameters.kCellsAtMostSameBy = 1.0;
|
||||||
|
parameters.kAtLeastOptimalAroundViaBy = 0.2;
|
||||||
|
parameters.kAtMostSameBy = 0.50;
|
||||||
|
}
|
||||||
|
// 20km
|
||||||
|
else if (distance < 20000.)
|
||||||
|
{
|
||||||
|
parameters.kAlternativesToUnpackFactor = 8.0;
|
||||||
|
parameters.kCellsAtMostSameBy = 1.0;
|
||||||
|
parameters.kAtLeastOptimalAroundViaBy = 0.2;
|
||||||
|
parameters.kAtMostSameBy = 0.60;
|
||||||
|
}
|
||||||
|
// 50km
|
||||||
|
else if (distance < 50000.)
|
||||||
|
{
|
||||||
|
parameters.kAlternativesToUnpackFactor = 6.0;
|
||||||
|
parameters.kCellsAtMostSameBy = 0.95;
|
||||||
|
parameters.kAtMostSameBy = 0.65;
|
||||||
|
}
|
||||||
|
// 100km
|
||||||
|
else if (distance < 100000.)
|
||||||
|
{
|
||||||
|
parameters.kAlternativesToUnpackFactor = 4.0;
|
||||||
|
parameters.kCellsAtMostSameBy = 0.95;
|
||||||
|
parameters.kAtMostSameBy = 0.70;
|
||||||
|
}
|
||||||
|
|
||||||
|
return parameters;
|
||||||
|
}
|
||||||
|
|
||||||
// Filters candidates which are on not unique.
|
// Filters candidates which are on not unique.
|
||||||
// Returns an iterator to the uniquified range's new end.
|
// Returns an iterator to the uniquified range's new end.
|
||||||
// Note: mutates the range in-place invalidating iterators.
|
// Note: mutates the range in-place invalidating iterators.
|
||||||
@@ -110,49 +208,13 @@ RandIt filterViaCandidatesByRoadImportance(RandIt first, RandIt last, const Faca
|
|||||||
return last;
|
return last;
|
||||||
}
|
}
|
||||||
|
|
||||||
// Scale the maximum allowed weight increase based on its magnitude:
|
|
||||||
// - Shortest path 10 minutes, alternative 13 minutes => Factor of 0.30 ok
|
|
||||||
// - Shortest path 10 hours, alternative 13 hours => Factor of 0.30 unreasonable
|
|
||||||
double scaledAtMostLongerByFactorBasedOnDuration(EdgeWeight duration)
|
|
||||||
{
|
|
||||||
BOOST_ASSERT(duration != INVALID_EDGE_WEIGHT);
|
|
||||||
|
|
||||||
// We only have generic weights here and no durations without unpacking.
|
|
||||||
// We also have restricted way penalties which are huge and will screw scaling here.
|
|
||||||
//
|
|
||||||
// Users can pass us generic weights not based on durations; we can't do anything about
|
|
||||||
// it here other than either generating too many or no alternatives in these cases.
|
|
||||||
//
|
|
||||||
// We scale the weights with a step function based on some rough guestimates, so that
|
|
||||||
// they match tens of minutes, in the low hours, tens of hours, etc.
|
|
||||||
|
|
||||||
// Todo: instead of a piecewise constant function should this be a continuous function?
|
|
||||||
// At the moment there are "hard" jump edge cases when crossing the thresholds.
|
|
||||||
|
|
||||||
auto scaledAtMostLongerBy = kAtMostLongerBy;
|
|
||||||
|
|
||||||
const constexpr auto minutes = 60.;
|
|
||||||
const constexpr auto hours = 60. * minutes;
|
|
||||||
|
|
||||||
if (duration < EdgeWeight(10 * minutes))
|
|
||||||
scaledAtMostLongerBy *= 1.20;
|
|
||||||
else if (duration < EdgeWeight(30 * minutes))
|
|
||||||
scaledAtMostLongerBy *= 1.00;
|
|
||||||
else if (duration < EdgeWeight(1 * hours))
|
|
||||||
scaledAtMostLongerBy *= 0.90;
|
|
||||||
else if (duration < EdgeWeight(3 * hours))
|
|
||||||
scaledAtMostLongerBy *= 0.70;
|
|
||||||
else if (duration > EdgeWeight(10 * hours))
|
|
||||||
scaledAtMostLongerBy *= 0.50;
|
|
||||||
|
|
||||||
return scaledAtMostLongerBy;
|
|
||||||
}
|
|
||||||
|
|
||||||
// Filters candidates with much higher weight than the primary route. Mutates range in-place.
|
// Filters candidates with much higher weight than the primary route. Mutates range in-place.
|
||||||
// Returns an iterator to the filtered range's new end.
|
// Returns an iterator to the filtered range's new end.
|
||||||
template <typename RandIt>
|
template <typename RandIt>
|
||||||
RandIt
|
RandIt filterViaCandidatesByStretch(RandIt first,
|
||||||
filterViaCandidatesByStretch(RandIt first, RandIt last, EdgeWeight weight, double weight_multiplier)
|
RandIt last,
|
||||||
|
const EdgeWeight weight,
|
||||||
|
const Parameters ¶meters)
|
||||||
{
|
{
|
||||||
util::static_assert_iter_category<RandIt, std::random_access_iterator_tag>();
|
util::static_assert_iter_category<RandIt, std::random_access_iterator_tag>();
|
||||||
util::static_assert_iter_value<RandIt, WeightedViaNode>();
|
util::static_assert_iter_value<RandIt, WeightedViaNode>();
|
||||||
@@ -160,9 +222,7 @@ filterViaCandidatesByStretch(RandIt first, RandIt last, EdgeWeight weight, doubl
|
|||||||
// Assumes weight roughly corresponds to duration-ish. If this is not the case e.g.
|
// Assumes weight roughly corresponds to duration-ish. If this is not the case e.g.
|
||||||
// because users are setting weight to be distance in the profiles, then we might
|
// because users are setting weight to be distance in the profiles, then we might
|
||||||
// either generate more candidates than we have to or not enough. But is okay.
|
// either generate more candidates than we have to or not enough. But is okay.
|
||||||
const auto scaled_at_most_longer_by =
|
const auto stretch_weight_limit = (1. + parameters.kAtMostLongerBy) * weight;
|
||||||
scaledAtMostLongerByFactorBasedOnDuration(weight / weight_multiplier);
|
|
||||||
const auto stretch_weight_limit = (1. + scaled_at_most_longer_by) * weight;
|
|
||||||
|
|
||||||
const auto over_weight_limit = [=](const auto via) {
|
const auto over_weight_limit = [=](const auto via) {
|
||||||
return via.weight > stretch_weight_limit;
|
return via.weight > stretch_weight_limit;
|
||||||
@@ -198,8 +258,15 @@ filterViaCandidatesByViaNotOnPath(const WeightedViaNodePackedPath &path, RandIt
|
|||||||
// Filters packed paths with similar cells between each other. Mutates range in-place.
|
// Filters packed paths with similar cells between each other. Mutates range in-place.
|
||||||
// Returns an iterator to the filtered range's new end.
|
// Returns an iterator to the filtered range's new end.
|
||||||
template <typename RandIt>
|
template <typename RandIt>
|
||||||
RandIt filterPackedPathsByCellSharing(RandIt first, RandIt last, const Partition &partition)
|
RandIt filterPackedPathsByCellSharing(RandIt first,
|
||||||
|
RandIt last,
|
||||||
|
const Partition &partition,
|
||||||
|
const Parameters ¶meters)
|
||||||
{
|
{
|
||||||
|
// In this case we don't need to calculate sharing, because it would not filter anything
|
||||||
|
if (parameters.kCellsAtMostSameBy >= 1.0)
|
||||||
|
return last;
|
||||||
|
|
||||||
util::static_assert_iter_category<RandIt, std::random_access_iterator_tag>();
|
util::static_assert_iter_category<RandIt, std::random_access_iterator_tag>();
|
||||||
util::static_assert_iter_value<RandIt, WeightedViaNodePackedPath>();
|
util::static_assert_iter_value<RandIt, WeightedViaNodePackedPath>();
|
||||||
|
|
||||||
@@ -226,14 +293,13 @@ RandIt filterPackedPathsByCellSharing(RandIt first, RandIt last, const Partition
|
|||||||
return last;
|
return last;
|
||||||
|
|
||||||
std::unordered_set<CellID> cells;
|
std::unordered_set<CellID> cells;
|
||||||
cells.reserve(size * (shortest_path.path.size() + 1) * (1. + kAtMostLongerBy));
|
cells.reserve(size * (shortest_path.path.size() + 1) * (1 + parameters.kAtMostLongerBy));
|
||||||
|
|
||||||
cells.insert(get_cell(std::get<0>(shortest_path.path.front())));
|
cells.insert(get_cell(std::get<0>(shortest_path.path.front())));
|
||||||
for (const auto &edge : shortest_path.path)
|
for (const auto &edge : shortest_path.path)
|
||||||
cells.insert(get_cell(std::get<1>(edge)));
|
cells.insert(get_cell(std::get<1>(edge)));
|
||||||
|
|
||||||
const auto over_sharing_limit = [&](const auto &packed) {
|
const auto over_sharing_limit = [&](const auto &packed) {
|
||||||
|
|
||||||
if (packed.path.empty())
|
if (packed.path.empty())
|
||||||
{ // don't remove routes with single-node (empty) path
|
{ // don't remove routes with single-node (empty) path
|
||||||
return false;
|
return false;
|
||||||
@@ -253,7 +319,7 @@ RandIt filterPackedPathsByCellSharing(RandIt first, RandIt last, const Partition
|
|||||||
|
|
||||||
const auto sharing = 1. - difference;
|
const auto sharing = 1. - difference;
|
||||||
|
|
||||||
if (sharing > kAtLeastDifferentBy)
|
if (sharing > parameters.kCellsAtMostSameBy)
|
||||||
{
|
{
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
@@ -277,7 +343,8 @@ RandIt filterPackedPathsByLocalOptimality(const WeightedViaNodePackedPath &path,
|
|||||||
const Heap &forward_heap,
|
const Heap &forward_heap,
|
||||||
const Heap &reverse_heap,
|
const Heap &reverse_heap,
|
||||||
RandIt first,
|
RandIt first,
|
||||||
RandIt last)
|
RandIt last,
|
||||||
|
const Parameters ¶meters)
|
||||||
{
|
{
|
||||||
util::static_assert_iter_category<RandIt, std::random_access_iterator_tag>();
|
util::static_assert_iter_category<RandIt, std::random_access_iterator_tag>();
|
||||||
util::static_assert_iter_value<RandIt, WeightedViaNodePackedPath>();
|
util::static_assert_iter_value<RandIt, WeightedViaNodePackedPath>();
|
||||||
@@ -376,7 +443,7 @@ RandIt filterPackedPathsByLocalOptimality(const WeightedViaNodePackedPath &path,
|
|||||||
const auto detour_length = forward_heap.GetKey(via) - forward_heap.GetKey(a) +
|
const auto detour_length = forward_heap.GetKey(via) - forward_heap.GetKey(a) +
|
||||||
reverse_heap.GetKey(via) - reverse_heap.GetKey(b);
|
reverse_heap.GetKey(via) - reverse_heap.GetKey(b);
|
||||||
|
|
||||||
return plateaux_length < kAtLeastOptimalAroundViaBy * detour_length;
|
return plateaux_length < parameters.kAtLeastOptimalAroundViaBy * detour_length;
|
||||||
};
|
};
|
||||||
|
|
||||||
return std::remove_if(first, last, is_not_locally_optimal);
|
return std::remove_if(first, last, is_not_locally_optimal);
|
||||||
@@ -384,7 +451,11 @@ RandIt filterPackedPathsByLocalOptimality(const WeightedViaNodePackedPath &path,
|
|||||||
|
|
||||||
// Filters unpacked paths compared to all other paths. Mutates range in-place.
|
// Filters unpacked paths compared to all other paths. Mutates range in-place.
|
||||||
// Returns an iterator to the filtered range's new end.
|
// Returns an iterator to the filtered range's new end.
|
||||||
template <typename RandIt> RandIt filterUnpackedPathsBySharing(RandIt first, RandIt last)
|
template <typename RandIt>
|
||||||
|
RandIt filterUnpackedPathsBySharing(RandIt first,
|
||||||
|
RandIt last,
|
||||||
|
const Facade &facade,
|
||||||
|
const Parameters ¶meters)
|
||||||
{
|
{
|
||||||
util::static_assert_iter_category<RandIt, std::random_access_iterator_tag>();
|
util::static_assert_iter_category<RandIt, std::random_access_iterator_tag>();
|
||||||
util::static_assert_iter_value<RandIt, WeightedViaNodeUnpackedPath>();
|
util::static_assert_iter_value<RandIt, WeightedViaNodeUnpackedPath>();
|
||||||
@@ -399,46 +470,59 @@ template <typename RandIt> RandIt filterUnpackedPathsBySharing(RandIt first, Ran
|
|||||||
if (shortest_path.edges.empty())
|
if (shortest_path.edges.empty())
|
||||||
return last;
|
return last;
|
||||||
|
|
||||||
std::unordered_set<EdgeID> edges;
|
std::unordered_set<NodeID> nodes;
|
||||||
edges.reserve(size * shortest_path.edges.size() * (1. + kAtMostLongerBy));
|
nodes.reserve(size * shortest_path.nodes.size() * (1.25));
|
||||||
|
|
||||||
edges.insert(begin(shortest_path.edges), begin(shortest_path.edges));
|
nodes.insert(begin(shortest_path.nodes), end(shortest_path.nodes));
|
||||||
|
|
||||||
const auto over_sharing_limit = [&](const auto &unpacked) {
|
|
||||||
|
|
||||||
|
const auto over_sharing_limit = [&](auto &unpacked) {
|
||||||
if (unpacked.edges.empty())
|
if (unpacked.edges.empty())
|
||||||
{ // don't remove routes with single-node (empty) path
|
{ // don't remove routes with single-node (empty) path
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
const auto not_seen = [&](const EdgeID edge) { return edges.count(edge) < 1; };
|
EdgeWeight total_duration = 0;
|
||||||
const auto different = std::count_if(begin(unpacked.edges), end(unpacked.edges), not_seen);
|
const auto add_if_seen = [&](const EdgeWeight duration, const NodeID node) {
|
||||||
|
auto node_duration = facade.GetNodeDuration(node);
|
||||||
|
total_duration += node_duration;
|
||||||
|
if (nodes.count(node) > 0)
|
||||||
|
{
|
||||||
|
return duration + node_duration;
|
||||||
|
}
|
||||||
|
return duration;
|
||||||
|
};
|
||||||
|
|
||||||
const auto difference = different / static_cast<double>(unpacked.edges.size());
|
const auto shared_duration = std::accumulate(
|
||||||
BOOST_ASSERT(difference >= 0.);
|
begin(unpacked.nodes), end(unpacked.nodes), EdgeDuration{0}, add_if_seen);
|
||||||
BOOST_ASSERT(difference <= 1.);
|
|
||||||
|
|
||||||
const auto sharing = 1. - difference;
|
unpacked.sharing = shared_duration / static_cast<double>(total_duration);
|
||||||
|
BOOST_ASSERT(unpacked.sharing >= 0.);
|
||||||
|
BOOST_ASSERT(unpacked.sharing <= 1.);
|
||||||
|
|
||||||
if (sharing > kAtLeastDifferentBy)
|
if (unpacked.sharing > parameters.kAtMostSameBy)
|
||||||
{
|
{
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
edges.insert(begin(unpacked.edges), end(unpacked.edges));
|
nodes.insert(begin(unpacked.nodes), end(unpacked.nodes));
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
return std::remove_if(first + 1, last, over_sharing_limit);
|
auto end = std::remove_if(first + 1, last, over_sharing_limit);
|
||||||
|
std::sort(
|
||||||
|
first + 1, end, [](const auto &lhs, const auto &rhs) { return lhs.sharing < rhs.sharing; });
|
||||||
|
return end;
|
||||||
}
|
}
|
||||||
|
|
||||||
// Filters annotated routes by stretch based on duration. Mutates range in-place.
|
// Filters annotated routes by stretch based on duration. Mutates range in-place.
|
||||||
// Returns an iterator to the filtered range's new end.
|
// Returns an iterator to the filtered range's new end.
|
||||||
template <typename RandIt>
|
template <typename RandIt>
|
||||||
RandIt
|
RandIt filterAnnotatedRoutesByStretch(RandIt first,
|
||||||
filterAnnotatedRoutesByStretch(RandIt first, RandIt last, const InternalRouteResult &shortest_route)
|
RandIt last,
|
||||||
|
const InternalRouteResult &shortest_route,
|
||||||
|
const Parameters ¶meters)
|
||||||
{
|
{
|
||||||
util::static_assert_iter_category<RandIt, std::random_access_iterator_tag>();
|
util::static_assert_iter_category<RandIt, std::random_access_iterator_tag>();
|
||||||
util::static_assert_iter_value<RandIt, InternalRouteResult>();
|
util::static_assert_iter_value<RandIt, InternalRouteResult>();
|
||||||
@@ -446,9 +530,7 @@ filterAnnotatedRoutesByStretch(RandIt first, RandIt last, const InternalRouteRes
|
|||||||
BOOST_ASSERT(shortest_route.is_valid());
|
BOOST_ASSERT(shortest_route.is_valid());
|
||||||
|
|
||||||
const auto shortest_route_duration = shortest_route.duration();
|
const auto shortest_route_duration = shortest_route.duration();
|
||||||
const auto scaled_at_most_longer_by =
|
const auto stretch_duration_limit = (1. + parameters.kAtMostLongerBy) * shortest_route_duration;
|
||||||
scaledAtMostLongerByFactorBasedOnDuration(shortest_route_duration);
|
|
||||||
const auto stretch_duration_limit = (1. + scaled_at_most_longer_by) * shortest_route_duration;
|
|
||||||
|
|
||||||
const auto over_duration_limit = [=](const auto &route) {
|
const auto over_duration_limit = [=](const auto &route) {
|
||||||
return route.duration() > stretch_duration_limit;
|
return route.duration() > stretch_duration_limit;
|
||||||
@@ -559,6 +641,7 @@ void unpackPackedPaths(InputIt first,
|
|||||||
}
|
}
|
||||||
|
|
||||||
WeightedViaNodeUnpackedPath unpacked_path{
|
WeightedViaNodeUnpackedPath unpacked_path{
|
||||||
|
0.0,
|
||||||
WeightedViaNode{packed_path_via, packed_path_weight},
|
WeightedViaNode{packed_path_via, packed_path_weight},
|
||||||
std::move(unpacked_nodes),
|
std::move(unpacked_nodes),
|
||||||
std::move(unpacked_edges)};
|
std::move(unpacked_edges)};
|
||||||
@@ -573,7 +656,8 @@ void unpackPackedPaths(InputIt first,
|
|||||||
inline std::vector<WeightedViaNode>
|
inline std::vector<WeightedViaNode>
|
||||||
makeCandidateVias(SearchEngineData<Algorithm> &search_engine_data,
|
makeCandidateVias(SearchEngineData<Algorithm> &search_engine_data,
|
||||||
const Facade &facade,
|
const Facade &facade,
|
||||||
const PhantomNodes &phantom_node_pair)
|
const PhantomNodes &phantom_node_pair,
|
||||||
|
const Parameters ¶meters)
|
||||||
{
|
{
|
||||||
Heap &forward_heap = *search_engine_data.forward_heap_1;
|
Heap &forward_heap = *search_engine_data.forward_heap_1;
|
||||||
Heap &reverse_heap = *search_engine_data.reverse_heap_1;
|
Heap &reverse_heap = *search_engine_data.reverse_heap_1;
|
||||||
@@ -605,7 +689,7 @@ makeCandidateVias(SearchEngineData<Algorithm> &search_engine_data,
|
|||||||
while (forward_heap.Size() + reverse_heap.Size() > 0)
|
while (forward_heap.Size() + reverse_heap.Size() > 0)
|
||||||
{
|
{
|
||||||
if (shortest_path_weight != INVALID_EDGE_WEIGHT)
|
if (shortest_path_weight != INVALID_EDGE_WEIGHT)
|
||||||
overlap_weight = shortest_path_weight * kSearchSpaceOverlapFactor;
|
overlap_weight = shortest_path_weight * parameters.kSearchSpaceOverlapFactor;
|
||||||
|
|
||||||
// Termination criteria - when we have a shortest path this will guarantee for our overlap.
|
// Termination criteria - when we have a shortest path this will guarantee for our overlap.
|
||||||
const bool keep_going = forward_heap_min + reverse_heap_min < overlap_weight;
|
const bool keep_going = forward_heap_min + reverse_heap_min < overlap_weight;
|
||||||
@@ -670,7 +754,7 @@ makeCandidateVias(SearchEngineData<Algorithm> &search_engine_data,
|
|||||||
return candidate_vias;
|
return candidate_vias;
|
||||||
}
|
}
|
||||||
|
|
||||||
} // anon. ns
|
} // namespace
|
||||||
|
|
||||||
// Alternative Routes for MLD.
|
// Alternative Routes for MLD.
|
||||||
//
|
//
|
||||||
@@ -691,9 +775,11 @@ InternalManyRoutesResult alternativePathSearch(SearchEngineData<Algorithm> &sear
|
|||||||
const PhantomNodes &phantom_node_pair,
|
const PhantomNodes &phantom_node_pair,
|
||||||
unsigned number_of_alternatives)
|
unsigned number_of_alternatives)
|
||||||
{
|
{
|
||||||
|
Parameters parameters = parametersFromRequest(phantom_node_pair);
|
||||||
|
|
||||||
const auto max_number_of_alternatives = number_of_alternatives;
|
const auto max_number_of_alternatives = number_of_alternatives;
|
||||||
const auto max_number_of_alternatives_to_unpack =
|
const auto max_number_of_alternatives_to_unpack =
|
||||||
kAlternativesToUnpackFactor * max_number_of_alternatives;
|
parameters.kAlternativesToUnpackFactor * max_number_of_alternatives;
|
||||||
BOOST_ASSERT(max_number_of_alternatives > 0);
|
BOOST_ASSERT(max_number_of_alternatives > 0);
|
||||||
BOOST_ASSERT(max_number_of_alternatives_to_unpack >= max_number_of_alternatives);
|
BOOST_ASSERT(max_number_of_alternatives_to_unpack >= max_number_of_alternatives);
|
||||||
|
|
||||||
@@ -707,7 +793,8 @@ InternalManyRoutesResult alternativePathSearch(SearchEngineData<Algorithm> &sear
|
|||||||
Heap &reverse_heap = *search_engine_data.reverse_heap_1;
|
Heap &reverse_heap = *search_engine_data.reverse_heap_1;
|
||||||
|
|
||||||
// Do forward and backward search, save search space overlap as via candidates.
|
// Do forward and backward search, save search space overlap as via candidates.
|
||||||
auto candidate_vias = makeCandidateVias(search_engine_data, facade, phantom_node_pair);
|
auto candidate_vias =
|
||||||
|
makeCandidateVias(search_engine_data, facade, phantom_node_pair, parameters);
|
||||||
|
|
||||||
const auto by_weight = [](const auto &lhs, const auto &rhs) { return lhs.weight < rhs.weight; };
|
const auto by_weight = [](const auto &lhs, const auto &rhs) { return lhs.weight < rhs.weight; };
|
||||||
auto shortest_path_via_it =
|
auto shortest_path_via_it =
|
||||||
@@ -730,6 +817,9 @@ InternalManyRoutesResult alternativePathSearch(SearchEngineData<Algorithm> &sear
|
|||||||
NodeID shortest_path_via = shortest_path_via_it->node;
|
NodeID shortest_path_via = shortest_path_via_it->node;
|
||||||
EdgeWeight shortest_path_weight = shortest_path_via_it->weight;
|
EdgeWeight shortest_path_weight = shortest_path_via_it->weight;
|
||||||
|
|
||||||
|
const double duration_estimation = shortest_path_weight / facade.GetWeightMultiplier();
|
||||||
|
parameters.kAtMostLongerBy = getLongerByFactorBasedOnDuration(duration_estimation);
|
||||||
|
|
||||||
// Filters via candidate nodes with heuristics
|
// Filters via candidate nodes with heuristics
|
||||||
|
|
||||||
// Note: filter pipeline below only makes range smaller; no need to erase items
|
// Note: filter pipeline below only makes range smaller; no need to erase items
|
||||||
@@ -738,8 +828,7 @@ InternalManyRoutesResult alternativePathSearch(SearchEngineData<Algorithm> &sear
|
|||||||
|
|
||||||
it = filterViaCandidatesByUniqueNodeIds(begin(candidate_vias), it);
|
it = filterViaCandidatesByUniqueNodeIds(begin(candidate_vias), it);
|
||||||
it = filterViaCandidatesByRoadImportance(begin(candidate_vias), it, facade);
|
it = filterViaCandidatesByRoadImportance(begin(candidate_vias), it, facade);
|
||||||
it = filterViaCandidatesByStretch(
|
it = filterViaCandidatesByStretch(begin(candidate_vias), it, shortest_path_weight, parameters);
|
||||||
begin(candidate_vias), it, shortest_path_weight, facade.GetWeightMultiplier());
|
|
||||||
|
|
||||||
// Pre-rank by weight; sharing filtering below then discards by similarity.
|
// Pre-rank by weight; sharing filtering below then discards by similarity.
|
||||||
std::sort(begin(candidate_vias), it, [](const auto lhs, const auto rhs) {
|
std::sort(begin(candidate_vias), it, [](const auto lhs, const auto rhs) {
|
||||||
@@ -783,10 +872,10 @@ InternalManyRoutesResult alternativePathSearch(SearchEngineData<Algorithm> &sear
|
|||||||
forward_heap, // paths for s, via
|
forward_heap, // paths for s, via
|
||||||
reverse_heap, // paths for via, t
|
reverse_heap, // paths for via, t
|
||||||
begin(weighted_packed_paths) + 1,
|
begin(weighted_packed_paths) + 1,
|
||||||
alternative_paths_last);
|
alternative_paths_last,
|
||||||
|
parameters);
|
||||||
alternative_paths_last = filterPackedPathsByCellSharing(
|
alternative_paths_last = filterPackedPathsByCellSharing(
|
||||||
begin(weighted_packed_paths), alternative_paths_last, partition);
|
begin(weighted_packed_paths), alternative_paths_last, partition, parameters);
|
||||||
|
|
||||||
BOOST_ASSERT(weighted_packed_paths.size() >= 1);
|
BOOST_ASSERT(weighted_packed_paths.size() >= 1);
|
||||||
|
|
||||||
@@ -816,7 +905,8 @@ InternalManyRoutesResult alternativePathSearch(SearchEngineData<Algorithm> &sear
|
|||||||
|
|
||||||
auto unpacked_paths_last = end(unpacked_paths);
|
auto unpacked_paths_last = end(unpacked_paths);
|
||||||
|
|
||||||
unpacked_paths_last = filterUnpackedPathsBySharing(begin(unpacked_paths), end(unpacked_paths));
|
unpacked_paths_last = filterUnpackedPathsBySharing(
|
||||||
|
begin(unpacked_paths), end(unpacked_paths), facade, parameters);
|
||||||
|
|
||||||
const auto unpacked_paths_first = begin(unpacked_paths);
|
const auto unpacked_paths_first = begin(unpacked_paths);
|
||||||
const auto number_of_unpacked_paths =
|
const auto number_of_unpacked_paths =
|
||||||
@@ -850,7 +940,9 @@ InternalManyRoutesResult alternativePathSearch(SearchEngineData<Algorithm> &sear
|
|||||||
|
|
||||||
if (routes.size() > 1)
|
if (routes.size() > 1)
|
||||||
{
|
{
|
||||||
routes_last = filterAnnotatedRoutesByStretch(routes_first + 1, routes_last, *routes_first);
|
parameters.kAtMostLongerBy = getLongerByFactorBasedOnDuration(routes_first->duration());
|
||||||
|
routes_last = filterAnnotatedRoutesByStretch(
|
||||||
|
routes_first + 1, routes_last, *routes_first, parameters);
|
||||||
routes.erase(routes_last, end(routes));
|
routes.erase(routes_last, end(routes));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -1,5 +1,4 @@
|
|||||||
#include "engine/routing_algorithms/direct_shortest_path.hpp"
|
#include "engine/routing_algorithms/direct_shortest_path.hpp"
|
||||||
|
|
||||||
#include "engine/routing_algorithms/routing_base.hpp"
|
#include "engine/routing_algorithms/routing_base.hpp"
|
||||||
#include "engine/routing_algorithms/routing_base_ch.hpp"
|
#include "engine/routing_algorithms/routing_base_ch.hpp"
|
||||||
#include "engine/routing_algorithms/routing_base_mld.hpp"
|
#include "engine/routing_algorithms/routing_base_mld.hpp"
|
||||||
|
|||||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user