Compare commits
42 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
| 4b1a2cea6d | |||
| 31d6bfbf12 | |||
| 607fbce1ef | |||
| 06330a694e | |||
| cbecdf8a4f | |||
| dc26f7d8b9 | |||
| 791f6d02e1 | |||
| 7b7871d5aa | |||
| f7613d77d5 | |||
| c80edef46c | |||
| cfae4a1923 | |||
| fd9d5af7e0 | |||
| c81942c167 | |||
| c5c4a1b4fe | |||
| eb13041784 | |||
| fa1f121b02 | |||
| c26642de6e | |||
| ef1fc8a757 | |||
| 168e313f73 | |||
| 30f910e861 | |||
| e998c1193d | |||
| a8f3474996 | |||
| 55cc06fd8b | |||
| 8883d8cc56 | |||
| 5b2af6ef09 | |||
| 6d801e7086 | |||
| 17eb7052ba | |||
| 330f25eddb | |||
| 08b88bad63 | |||
| 153f9b02a5 | |||
| 0568dca4a3 | |||
| 60ef179d18 | |||
| c64904f5ea | |||
| 4b9e3a8068 | |||
| db7c76d04d | |||
| cc1a5ea78d | |||
| 9c033ff461 | |||
| 3c3322173c | |||
| e805f85407 | |||
| 4d54456f66 | |||
| 7359d0542f | |||
| da4fb13aa3 |
+1
-1
@@ -12,7 +12,7 @@ notifications:
|
|||||||
|
|
||||||
branches:
|
branches:
|
||||||
only:
|
only:
|
||||||
- master
|
- 5.15
|
||||||
# enable building tags
|
# enable building tags
|
||||||
- /^v\d+\.\d+(\.\d+)?(-\S*)?$/
|
- /^v\d+\.\d+(\.\d+)?(-\S*)?$/
|
||||||
|
|
||||||
|
|||||||
+24
-1
@@ -1,12 +1,35 @@
|
|||||||
# UNRELEASED
|
# 5.15.2
|
||||||
|
- Changes from 5.15.1:
|
||||||
|
- Features:
|
||||||
|
- Exposed the waypoints parameter in the node bindings interface
|
||||||
|
- Bugfixes:
|
||||||
|
- Segfault causing bug in leg collapsing map matching when traversing edges in reverse
|
||||||
|
|
||||||
|
# 5.15.1
|
||||||
|
- Changes from 5.15.0:
|
||||||
|
- Bugfixes:
|
||||||
|
- FIXED: Segfault in map matching when RouteLeg collapsing code is run on a match with multiple submatches
|
||||||
|
- Guidance:
|
||||||
|
- Set type of trivial intersections where classes change to Suppressed instead of NoTurn
|
||||||
|
|
||||||
|
# 5.15.0
|
||||||
- Changes from 5.14.3:
|
- Changes from 5.14.3:
|
||||||
- Bugfixes:
|
- Bugfixes:
|
||||||
- FIXED #4704: Fixed regression in bearings reordering introduced in 5.13 [#4704](https://github.com/Project-OSRM/osrm-backend/issues/4704)
|
- FIXED #4704: Fixed regression in bearings reordering introduced in 5.13 [#4704](https://github.com/Project-OSRM/osrm-backend/issues/4704)
|
||||||
|
- FIXED #4781: Fixed overflow exceptions in percent-encoding parsing
|
||||||
|
- FIXED #4770: Fixed exclude flags for single toll road scenario
|
||||||
|
- FIXED #4283: Fix overflow on zero duration segments
|
||||||
|
- FIXED #4804: Ignore no_*_on_red turn restrictions
|
||||||
- Guidance:
|
- Guidance:
|
||||||
- CHANGED #4706: Guidance refactoring step to decouple intersection connectivity analysis and turn instructions generation [#4706](https://github.com/Project-OSRM/osrm-backend/pull/4706)
|
- CHANGED #4706: Guidance refactoring step to decouple intersection connectivity analysis and turn instructions generation [#4706](https://github.com/Project-OSRM/osrm-backend/pull/4706)
|
||||||
|
- CHANGED #3491: Refactor `isThroughStreet`/Intersection options
|
||||||
|
- Profile:
|
||||||
|
- ADDED: `tunnel` as a new class in car profile so that sections of the route with tunnel tags will be marked as such
|
||||||
|
|
||||||
# 5.14.3
|
# 5.14.3
|
||||||
- Changes from 5.14.2:
|
- Changes from 5.14.2:
|
||||||
|
- Features:
|
||||||
|
- Added a `waypoints` parameter to the match service plugin that accepts indices to input coordinates and treats only those points as waypoints in the response format.
|
||||||
- Bugfixes:
|
- Bugfixes:
|
||||||
- FIXED #4754: U-Turn penalties are applied to straight turns.
|
- FIXED #4754: U-Turn penalties are applied to straight turns.
|
||||||
- FIXED #4756: Removed too restrictive road name check in the sliproad handler
|
- FIXED #4756: Removed too restrictive road name check in the sliproad handler
|
||||||
|
|||||||
+1
-1
@@ -62,7 +62,7 @@ endif()
|
|||||||
project(OSRM C CXX)
|
project(OSRM C CXX)
|
||||||
set(OSRM_VERSION_MAJOR 5)
|
set(OSRM_VERSION_MAJOR 5)
|
||||||
set(OSRM_VERSION_MINOR 15)
|
set(OSRM_VERSION_MINOR 15)
|
||||||
set(OSRM_VERSION_PATCH 0)
|
set(OSRM_VERSION_PATCH 2)
|
||||||
set(OSRM_VERSION "${OSRM_VERSION_MAJOR}.${OSRM_VERSION_MINOR}.${OSRM_VERSION_PATCH}")
|
set(OSRM_VERSION "${OSRM_VERSION_MAJOR}.${OSRM_VERSION_MINOR}.${OSRM_VERSION_PATCH}")
|
||||||
|
|
||||||
add_definitions(-DOSRM_PROJECT_DIR="${CMAKE_CURRENT_SOURCE_DIR}")
|
add_definitions(-DOSRM_PROJECT_DIR="${CMAKE_CURRENT_SOURCE_DIR}")
|
||||||
|
|||||||
@@ -114,7 +114,8 @@ sudo cmake --build . --target install
|
|||||||
|
|
||||||
### Request Against the Demo Server
|
### Request Against the Demo Server
|
||||||
|
|
||||||
Read the [API usage policy](https://github.com/Project-OSRM/osrm-backend/wiki/Api-usage-policy).
|
Read the [API usage policy](https://github.com/Project-OSRM/osrm-backend/wiki/Demo-server).
|
||||||
|
|
||||||
Simple query with instructions and alternatives on Berlin:
|
Simple query with instructions and alternatives on Berlin:
|
||||||
|
|
||||||
```
|
```
|
||||||
|
|||||||
@@ -288,6 +288,7 @@ In addition to the [general options](#general-options) the following options are
|
|||||||
|radiuses |`{radius};{radius}[;{radius} ...]` |Standard deviation of GPS precision used for map matching. If applicable use GPS accuracy.|
|
|radiuses |`{radius};{radius}[;{radius} ...]` |Standard deviation of GPS precision used for map matching. If applicable use GPS accuracy.|
|
||||||
|gaps |`split` (default), `ignore` |Allows the input track splitting based on huge timestamp gaps between points. |
|
|gaps |`split` (default), `ignore` |Allows the input track splitting based on huge timestamp gaps between points. |
|
||||||
|tidy |`true`, `false` (default) |Allows the input track modification to obtain better matching quality for noisy tracks. |
|
|tidy |`true`, `false` (default) |Allows the input track modification to obtain better matching quality for noisy tracks. |
|
||||||
|
|waypoints | `{index};{index};{index}...` |Treats input coordinates indicated by given indices as waypoints in returned Match object. Default is to treat all input coordinates as waypoints. |
|
||||||
|
|
||||||
|Parameter |Values |
|
|Parameter |Values |
|
||||||
|------------|-----------------------------------|
|
|------------|-----------------------------------|
|
||||||
|
|||||||
+13
-10
@@ -208,16 +208,19 @@ The `process_turn` function is called for every possible turn in the network. Ba
|
|||||||
|
|
||||||
The following attributes can be read and set on the result in `process_turn`:
|
The following attributes can be read and set on the result in `process_turn`:
|
||||||
|
|
||||||
Attribute | Read/write? | Type | Notes
|
Attribute | Read/write? | Type | Notes
|
||||||
-------------------|-------------|---------|------------------------------------------------------
|
---------------------|-------------|---------|------------------------------------------------------
|
||||||
direction_modifier | Read | Enum | Geometry of turn. Defined in `include/extractor/guidance/turn_instruction.hpp`
|
angle | Read | Float | Angle of turn in degrees (`0-360`: `0`=u-turn, `180`=straight on)
|
||||||
turn_type | Read | Enum | Priority of turn. Defined in `include/extractor/guidance/turn_instruction.hpp`
|
number_of_roads | Read | Integer | Number of ways at the intersection of the turn
|
||||||
has_traffic_light | Read | Boolean | Is a traffic light present at this turn?
|
is_u_turn | Read | Boolean | Is the turn a u-turn?
|
||||||
source_restricted | Read | Boolean | Is it from a restricted access road? (See definition in `process_way`)
|
has_traffic_light | Read | Boolean | Is a traffic light present at this turn?
|
||||||
target_restricted | Read | Boolean | Is it to a restricted access road? (See definition in `process_way`)
|
source_restricted | Read | Boolean | Is it from a restricted access road? (See definition in `process_way`)
|
||||||
angle | Read | Float | Angle of turn in degrees (`0-360`: `0`=u-turn, `180`=straight on)
|
target_restricted | Read | Boolean | Is it to a restricted access road? (See definition in `process_way`)
|
||||||
duration | Read/write | Float | Penalty to be applied for this turn (duration in deciseconds)
|
is_left_hand_driving | Read | Boolean | Is left-hand traffic?
|
||||||
weight | Read/write | Float | Penalty to be applied for this turn (routing weight)
|
weight | Read/write | Float | Penalty to be applied for this turn (routing weight)
|
||||||
|
duration | Read/write | Float | Penalty to be applied for this turn (duration in deciseconds)
|
||||||
|
source_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`
|
||||||
|
|
||||||
## Guidance
|
## Guidance
|
||||||
The guidance parameters in profiles are currently a work in progress. They can and will change.
|
The guidance parameters in profiles are currently a work in progress. They can and will change.
|
||||||
|
|||||||
@@ -82,7 +82,7 @@ Feature: Car - Mode flag
|
|||||||
| from | to | route | turns | classes |
|
| from | to | route | turns | classes |
|
||||||
| a | d | ab,cd | depart,arrive| [(restricted),(motorway,restricted),()],[()] |
|
| a | d | ab,cd | depart,arrive| [(restricted),(motorway,restricted),()],[()] |
|
||||||
|
|
||||||
Scenario: Car - We toll restricted with a class
|
Scenario: Car - We tag toll with a class
|
||||||
Given the node map
|
Given the node map
|
||||||
"""
|
"""
|
||||||
a b
|
a b
|
||||||
@@ -99,6 +99,45 @@ Feature: Car - Mode flag
|
|||||||
| from | to | route | turns | classes |
|
| from | to | route | turns | classes |
|
||||||
| a | d | ab,cd | depart,arrive | [(toll),(motorway,toll),()],[()] |
|
| a | d | ab,cd | depart,arrive | [(toll),(motorway,toll),()],[()] |
|
||||||
|
|
||||||
|
Scenario: Car - 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: Car - 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: Car - From roundabout on toll road
|
Scenario: Car - From roundabout on toll road
|
||||||
Given the node map
|
Given the node map
|
||||||
"""
|
"""
|
||||||
@@ -124,4 +163,3 @@ Feature: Car - Mode flag
|
|||||||
When I route I should get
|
When I route I should get
|
||||||
| from | to | route | turns | classes |
|
| from | to | route | turns | classes |
|
||||||
| a | f | ab,df,df,df | depart,roundabout-exit-2,exit roundabout slight right,arrive | [()],[(),(motorway)],[(toll,motorway)],[()] |
|
| a | f | ab,df,df,df | depart,roundabout-exit-2,exit roundabout slight right,arrive | [()],[(),(motorway)],[(toll,motorway)],[()] |
|
||||||
|
|
||||||
|
|||||||
@@ -141,6 +141,33 @@ Feature: Car - Turn restrictions
|
|||||||
| c | a | cj,aj,aj |
|
| c | a | cj,aj,aj |
|
||||||
| c | b | cj,bj,bj |
|
| c | b | cj,bj,bj |
|
||||||
|
|
||||||
|
@no_turning
|
||||||
|
Scenario: Car - Ignore no_*_on_red relations
|
||||||
|
Given the node map
|
||||||
|
"""
|
||||||
|
a
|
||||||
|
d j b
|
||||||
|
c
|
||||||
|
"""
|
||||||
|
|
||||||
|
And the ways
|
||||||
|
| nodes | oneway |
|
||||||
|
| cj | yes |
|
||||||
|
| aj | -1 |
|
||||||
|
| dj | -1 |
|
||||||
|
| bj | -1 |
|
||||||
|
|
||||||
|
And the relations
|
||||||
|
| type | way:from | way:to | node:via | restriction |
|
||||||
|
| restriction | cj | dj | j | no_turn_on_red |
|
||||||
|
| restriction | cj | bj | j | no_right_turn_on_red |
|
||||||
|
|
||||||
|
When I route I should get
|
||||||
|
| from | to | route |
|
||||||
|
| c | d | cj,dj,dj |
|
||||||
|
| c | a | cj,aj,aj |
|
||||||
|
| c | b | cj,bj,bj |
|
||||||
|
|
||||||
@only_turning
|
@only_turning
|
||||||
Scenario: Car - Only left turn
|
Scenario: Car - Only left turn
|
||||||
Given the node map
|
Given the node map
|
||||||
|
|||||||
@@ -98,11 +98,11 @@ Feature: Car - Guidance - Bridges and Tunnels
|
|||||||
| dce | primary | | Nebenstraße |
|
| dce | primary | | Nebenstraße |
|
||||||
|
|
||||||
When I route I should get
|
When I route I should get
|
||||||
| from | to | route | turns |
|
| from | to | route | turns |
|
||||||
| a | d | Hauptstraße,Nebenstraße,Nebenstraße | depart,turn left,arrive |
|
| a | d | Hauptstraße,Nebenstraße,Nebenstraße | depart,end of road left,arrive |
|
||||||
| a | e | Hauptstraße,Nebenstraße,Nebenstraße | depart,turn right,arrive |
|
| a | e | Hauptstraße,Nebenstraße,Nebenstraße | depart,end of road right,arrive |
|
||||||
| e | a | Nebenstraße,Hauptstraßentunnel,Hauptstraße | depart,turn left,arrive |
|
| e | a | Nebenstraße,Hauptstraßentunnel,Hauptstraße | depart,turn left,arrive |
|
||||||
| d | a | Nebenstraße,Hauptstraßentunnel,Hauptstraße | depart,turn right,arrive |
|
| d | a | Nebenstraße,Hauptstraßentunnel,Hauptstraße | depart,turn right,arrive |
|
||||||
|
|
||||||
Scenario: Tunnel with Immediate Turn Front and Back
|
Scenario: Tunnel with Immediate Turn Front and Back
|
||||||
Given the node map
|
Given the node map
|
||||||
@@ -129,4 +129,3 @@ Feature: Car - Guidance - Bridges and Tunnels
|
|||||||
| e | g | Nebenstraße,Hauptstraßentunnel,Anderestraße,Anderestraße | depart,turn left,turn left,arrive |
|
| e | g | Nebenstraße,Hauptstraßentunnel,Anderestraße,Anderestraße | depart,turn left,turn left,arrive |
|
||||||
| d | f | Nebenstraße,Hauptstraßentunnel,Anderestraße,Anderestraße | depart,turn right,turn right,arrive |
|
| d | f | Nebenstraße,Hauptstraßentunnel,Anderestraße,Anderestraße | depart,turn right,turn right,arrive |
|
||||||
| d | g | Nebenstraße,Hauptstraßentunnel,Anderestraße,Anderestraße | depart,turn right,turn left,arrive |
|
| d | g | Nebenstraße,Hauptstraßentunnel,Anderestraße,Anderestraße | depart,turn right,turn left,arrive |
|
||||||
|
|
||||||
|
|||||||
@@ -393,7 +393,7 @@ Feature: Merge Segregated Roads
|
|||||||
"""
|
"""
|
||||||
a
|
a
|
||||||
|
|
|
|
||||||
b
|
b-----z
|
||||||
/ \
|
/ \
|
||||||
c h
|
c h
|
||||||
| |
|
| |
|
||||||
@@ -402,6 +402,9 @@ Feature: Merge Segregated Roads
|
|||||||
| |
|
| |
|
||||||
| |
|
| |
|
||||||
| |
|
| |
|
||||||
|
| |
|
||||||
|
| |
|
||||||
|
| |
|
||||||
d g
|
d g
|
||||||
\ /
|
\ /
|
||||||
e
|
e
|
||||||
@@ -410,18 +413,24 @@ Feature: Merge Segregated Roads
|
|||||||
"""
|
"""
|
||||||
|
|
||||||
And the ways
|
And the ways
|
||||||
| nodes | name | oneway |
|
| nodes | name | oneway |
|
||||||
| ab | road | no |
|
| ab | road | no |
|
||||||
| ef | road | no |
|
| ef | road | no |
|
||||||
| bcde | road | yes |
|
| bcde | road | yes |
|
||||||
| eghb | road | yes |
|
| eghb | road | yes |
|
||||||
|
| bz | cross | no |
|
||||||
|
|
||||||
|
And the relations
|
||||||
|
| type | way:from | way:to | node:via | restriction |
|
||||||
|
| restriction | bz | bcde | b | no_left_turn |
|
||||||
|
|
||||||
When I route I should get
|
When I route I should get
|
||||||
| waypoints | turns | route |
|
| waypoints | turns | route |
|
||||||
| a,f | depart,arrive | road,road |
|
| a,f | depart,arrive | road,road |
|
||||||
| c,f | depart,arrive | road,road |
|
| c,f | depart,arrive | road,road |
|
||||||
| f,a | depart,arrive | road,road |
|
| f,a | depart,arrive | road,road |
|
||||||
| g,a | depart,arrive | road,road |
|
| g,a | depart,arrive | road,road |
|
||||||
|
| z,a | depart,turn right,arrive | cross,road,road |
|
||||||
|
|
||||||
Scenario: Traffic Island
|
Scenario: Traffic Island
|
||||||
Given the node map
|
Given the node map
|
||||||
@@ -592,10 +601,10 @@ Feature: Merge Segregated Roads
|
|||||||
|
|
||||||
When I route I should get
|
When I route I should get
|
||||||
| waypoints | route | turns |
|
| waypoints | route | turns |
|
||||||
| a,c | germ,ober | depart,arrive |
|
| a,c | germ,ober | depart,arrive |
|
||||||
| a,g | germ,germ,germ | depart,continue right,arrive |
|
| a,g | germ,germ,germ | depart,continue right,arrive |
|
||||||
| a,1 | germ,germ,germ | depart,continue left,arrive |
|
| a,1 | germ,germ,germ | depart,continue left,arrive |
|
||||||
| d,g | ober,germ,germ | depart,turn left,arrive |
|
| d,g | ober,germ,germ | depart,turn left,arrive |
|
||||||
|
|
||||||
# https://www.openstreetmap.org/#map=19/51.32888/6.57059
|
# https://www.openstreetmap.org/#map=19/51.32888/6.57059
|
||||||
Scenario: Places in presence of oneways
|
Scenario: Places in presence of oneways
|
||||||
@@ -627,16 +636,16 @@ Feature: Merge Segregated Roads
|
|||||||
| cf | albrecht | yes |
|
| cf | albrecht | yes |
|
||||||
|
|
||||||
When I route I should get
|
When I route I should get
|
||||||
| waypoints | route | turns |
|
| waypoints | route | turns |
|
||||||
| a,l | schwert,albrecht,marianne,marianne | depart,new name straight,turn left,arrive |
|
| a,l | schwert,albrecht,marianne,marianne | depart,new name straight,turn left,arrive |
|
||||||
| a,j | schwert,luise,luise | depart,turn right,arrive |
|
| a,j | schwert,luise,luise | depart,turn right,arrive |
|
||||||
| a,1 | schwert,albrecht,albrecht,albrecht | depart,new name straight,continue uturn,arrive |
|
| a,1 | schwert,albrecht,albrecht,albrecht | depart,new name straight,continue uturn,arrive |
|
||||||
| k,l | marianne,marianne | depart,arrive |
|
| k,l | marianne,marianne | depart,arrive |
|
||||||
| k,j | marianne,albrecht,luise,luise | depart,turn left,turn left,arrive |
|
| k,j | marianne,albrecht,luise,luise | depart,turn left,turn left,arrive |
|
||||||
| k,d | marianne,schwert,schwert | depart,turn right,arrive |
|
| k,d | marianne,schwert,schwert | depart,turn right,arrive |
|
||||||
| i,j | luise,luise | depart,arrive |
|
| i,j | luise,luise | depart,arrive |
|
||||||
| i,d | luise,albrecht,schwert,schwert | depart,turn left,turn straight,arrive |
|
| i,d | luise,albrecht,schwert,schwert | depart,turn left,turn straight,arrive |
|
||||||
| i,l | luise,albrecht,marianne,marianne | depart,turn left,turn left,arrive |
|
| i,l | luise,albrecht,marianne,marianne | depart,turn left,turn left,arrive |
|
||||||
|
|
||||||
# https://www.openstreetmap.org/#map=19/52.46339/13.40272
|
# https://www.openstreetmap.org/#map=19/52.46339/13.40272
|
||||||
Scenario: Do not merge links between segregated roads
|
Scenario: Do not merge links between segregated roads
|
||||||
|
|||||||
@@ -150,7 +150,8 @@ module.exports = function () {
|
|||||||
}
|
}
|
||||||
var ok = true;
|
var ok = true;
|
||||||
var encodedResult = '',
|
var encodedResult = '',
|
||||||
extendedTarget = '';
|
extendedTarget = '',
|
||||||
|
resultWaypoints = [];
|
||||||
|
|
||||||
var testSubMatching = (sub, si) => {
|
var testSubMatching = (sub, si) => {
|
||||||
var testSubNode = (ni) => {
|
var testSubNode = (ni) => {
|
||||||
@@ -186,6 +187,29 @@ module.exports = function () {
|
|||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (headers.has('waypoints')) {
|
||||||
|
var got_loc = [];
|
||||||
|
for (let i = 0; i < json.tracepoints.length; i++) {
|
||||||
|
if (!json.tracepoints[i]) continue;
|
||||||
|
if (json.tracepoints[i].waypoint_index != null)
|
||||||
|
got_loc.push(json.tracepoints[i].location);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (row.waypoints.length != got_loc.length)
|
||||||
|
return cb(new Error(`Expected ${row.waypoints.length} waypoints, got ${got_loc.length}`));
|
||||||
|
|
||||||
|
for (i = 0; i < row.waypoints.length; i++)
|
||||||
|
{
|
||||||
|
var want_node = this.findNodeByName(row.waypoints[i]);
|
||||||
|
if (!this.FuzzyMatch.matchLocation(got_loc[i], want_node)) {
|
||||||
|
resultWaypoints.push(util.format('? [%s,%s]', got_loc[i][0], got_loc[i][1]));
|
||||||
|
ok = false;
|
||||||
|
} else {
|
||||||
|
resultWaypoints.push(row.waypoints[i]);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
if (ok) {
|
if (ok) {
|
||||||
if (headers.has('matchings')) {
|
if (headers.has('matchings')) {
|
||||||
got.matchings = row.matchings;
|
got.matchings = row.matchings;
|
||||||
@@ -194,7 +218,12 @@ module.exports = function () {
|
|||||||
if (headers.has('timestamps')) {
|
if (headers.has('timestamps')) {
|
||||||
got.timestamps = row.timestamps;
|
got.timestamps = row.timestamps;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (headers.has('waypoints')) {
|
||||||
|
got.waypoints = row.waypoints;
|
||||||
|
}
|
||||||
} else {
|
} else {
|
||||||
|
got.waypoints = resultWaypoints.join(';');
|
||||||
got.matchings = encodedResult;
|
got.matchings = encodedResult;
|
||||||
row.matchings = extendedTarget;
|
row.matchings = extendedTarget;
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -59,3 +59,27 @@ Feature: Annotations
|
|||||||
| from | to | route | a:datasources | a:speed |
|
| from | to | route | a:datasources | a:speed |
|
||||||
| a | i | abcdefghi,abcdefghi | 1:0:1:0:1:0:0:0 | 50:10:50:10:50:10:10:10 |
|
| a | i | abcdefghi,abcdefghi | 1:0:1:0:1:0:0:0 | 50:10:50:10:50:10:10:10 |
|
||||||
| i | a | abcdefghi,abcdefghi | 0:1:0:0:0:0:0:1 | 10:50:10:10:10:10:10:50 |
|
| i | a | abcdefghi,abcdefghi | 0:1:0:0:0:0:0:1 | 10:50:10:10:10:10:10:50 |
|
||||||
|
|
||||||
|
Scenario: Speed annotations should handle zero segments
|
||||||
|
Given the profile "testbot"
|
||||||
|
|
||||||
|
Given the node map
|
||||||
|
"""
|
||||||
|
a -- b --- c
|
||||||
|
|
|
||||||
|
d
|
||||||
|
"""
|
||||||
|
|
||||||
|
And the ways
|
||||||
|
| nodes |
|
||||||
|
| abc |
|
||||||
|
| cd |
|
||||||
|
|
||||||
|
# This test relies on the snapping to the EBN cd to introduce a zero segment after the turn
|
||||||
|
And the query options
|
||||||
|
| annotations | speed,distance,duration,nodes |
|
||||||
|
| bearings | 90,5;180,5 |
|
||||||
|
|
||||||
|
When I route I should get
|
||||||
|
| from | to | route | a:speed | a:distance | a:duration | a:nodes |
|
||||||
|
| a | c | abc,abc | 10:10:10 | 249.998641:299.931643:0 | 25:30:0 | 1:2:3 |
|
||||||
|
|||||||
@@ -0,0 +1,68 @@
|
|||||||
|
@routing @testbot @exclude
|
||||||
|
Feature: Testbot - Exclude flags regression tests
|
||||||
|
Background:
|
||||||
|
Given the profile "testbot"
|
||||||
|
|
||||||
|
Scenario: Testbot - Exclude toll regression 1
|
||||||
|
Given the node map
|
||||||
|
"""
|
||||||
|
a g
|
||||||
|
. .
|
||||||
|
b....d-$-$-e....f
|
||||||
|
. .
|
||||||
|
c h
|
||||||
|
"""
|
||||||
|
|
||||||
|
And the ways
|
||||||
|
| nodes | highway | toll | # |
|
||||||
|
| ab | primary | | always drivable |
|
||||||
|
| cb | primary | | always drivable |
|
||||||
|
| bd | primary | | always drivable |
|
||||||
|
| de | motorway | yes | not drivable for exclude=toll |
|
||||||
|
| ef | primary | | always drivable |
|
||||||
|
| fg | primary | | always drivable |
|
||||||
|
| fh | primary | | always drivable |
|
||||||
|
|
||||||
|
Given the query options
|
||||||
|
| exclude | toll |
|
||||||
|
|
||||||
|
When I route I should get
|
||||||
|
| from | to | route |
|
||||||
|
| a | h | |
|
||||||
|
| a | g | |
|
||||||
|
| g | a | |
|
||||||
|
| d | e | |
|
||||||
|
|
||||||
|
Scenario: Testbot - Exclude toll regression 2
|
||||||
|
Given the profile "testbot"
|
||||||
|
|
||||||
|
Given the node map
|
||||||
|
"""
|
||||||
|
a g
|
||||||
|
. .
|
||||||
|
b....d-$-$-e....f
|
||||||
|
. .
|
||||||
|
c h..i
|
||||||
|
"""
|
||||||
|
|
||||||
|
And the ways
|
||||||
|
| nodes | highway | toll | # |
|
||||||
|
| ab | primary | | always drivable |
|
||||||
|
| cb | primary | | always drivable |
|
||||||
|
| bd | primary | | always drivable |
|
||||||
|
| de | motorway | yes | not drivable for exclude=toll |
|
||||||
|
| ef | primary | | always drivable |
|
||||||
|
| fg | primary | | always drivable |
|
||||||
|
| fh | primary | | always drivable |
|
||||||
|
| hi | primary | | always drivable |
|
||||||
|
|
||||||
|
Given the query options
|
||||||
|
| exclude | toll |
|
||||||
|
|
||||||
|
When I route I should get
|
||||||
|
| from | to | route |
|
||||||
|
| a | h | |
|
||||||
|
| a | g | |
|
||||||
|
| g | a | |
|
||||||
|
| d | e | |
|
||||||
|
| d | i | |
|
||||||
@@ -480,3 +480,149 @@ Feature: Basic Map Matching
|
|||||||
| trace | a:nodes |
|
| trace | a:nodes |
|
||||||
| 12 | 1:2:3:4:5:6 |
|
| 12 | 1:2:3:4:5:6 |
|
||||||
| 21 | 6:5:4:3:2:1 |
|
| 21 | 6:5:4:3:2:1 |
|
||||||
|
|
||||||
|
|
||||||
|
Scenario: Matching with waypoints param for start/end
|
||||||
|
Given the node map
|
||||||
|
"""
|
||||||
|
a-----b---c
|
||||||
|
|
|
||||||
|
|
|
||||||
|
d
|
||||||
|
|
|
||||||
|
|
|
||||||
|
e
|
||||||
|
"""
|
||||||
|
And the ways
|
||||||
|
| nodes | oneway |
|
||||||
|
| abc | no |
|
||||||
|
| bde | no |
|
||||||
|
|
||||||
|
Given the query options
|
||||||
|
| waypoints | 0;3 |
|
||||||
|
|
||||||
|
When I match I should get
|
||||||
|
| trace | code | matchings | waypoints |
|
||||||
|
| abde | Ok | abde | ae |
|
||||||
|
|
||||||
|
Scenario: Matching with waypoints param that were tidied away
|
||||||
|
Given the node map
|
||||||
|
"""
|
||||||
|
a - b - c - e
|
||||||
|
|
|
||||||
|
f
|
||||||
|
|
|
||||||
|
g
|
||||||
|
"""
|
||||||
|
And the ways
|
||||||
|
| nodes | oneway |
|
||||||
|
| abce | no |
|
||||||
|
| cfg | no |
|
||||||
|
|
||||||
|
Given the query options
|
||||||
|
| tidy | true |
|
||||||
|
| waypoints | 0;2;5 |
|
||||||
|
|
||||||
|
When I match I should get
|
||||||
|
| trace | code | matchings | waypoints |
|
||||||
|
| abccfg | Ok | abcfg | acg |
|
||||||
|
|
||||||
|
Scenario: Testbot - Map matching refuses to use waypoints with trace splitting
|
||||||
|
Given the node map
|
||||||
|
"""
|
||||||
|
a b c d
|
||||||
|
e
|
||||||
|
"""
|
||||||
|
Given the query options
|
||||||
|
| waypoints | 0;3 |
|
||||||
|
|
||||||
|
And the ways
|
||||||
|
| nodes | oneway |
|
||||||
|
| abcd | no |
|
||||||
|
|
||||||
|
When I match I should get
|
||||||
|
| trace | timestamps | code |
|
||||||
|
| abcd | 0 1 62 63 | NoMatch |
|
||||||
|
|
||||||
|
Scenario: Testbot - Map matching invalid waypoints
|
||||||
|
Given the node map
|
||||||
|
"""
|
||||||
|
a b c d
|
||||||
|
e
|
||||||
|
"""
|
||||||
|
Given the query options
|
||||||
|
| waypoints | 0;4 |
|
||||||
|
|
||||||
|
And the ways
|
||||||
|
| nodes | oneway |
|
||||||
|
| abcd | no |
|
||||||
|
|
||||||
|
When I match I should get
|
||||||
|
| trace | code |
|
||||||
|
| abcd | InvalidOptions |
|
||||||
|
|
||||||
|
Scenario: Matching fail with waypoints param missing start/end
|
||||||
|
Given the node map
|
||||||
|
"""
|
||||||
|
a-----b---c
|
||||||
|
|
|
||||||
|
|
|
||||||
|
d
|
||||||
|
|
|
||||||
|
|
|
||||||
|
e
|
||||||
|
"""
|
||||||
|
And the ways
|
||||||
|
| nodes | oneway |
|
||||||
|
| abc | no |
|
||||||
|
| bde | no |
|
||||||
|
|
||||||
|
Given the query options
|
||||||
|
| waypoints | 1;3 |
|
||||||
|
|
||||||
|
When I match I should get
|
||||||
|
| trace | code |
|
||||||
|
| abde | InvalidValue |
|
||||||
|
|
||||||
|
Scenario: Testbot - Map matching with outlier that has no candidate and waypoint parameter
|
||||||
|
Given a grid size of 100 meters
|
||||||
|
Given the node map
|
||||||
|
"""
|
||||||
|
a b c d
|
||||||
|
|
||||||
|
1
|
||||||
|
"""
|
||||||
|
|
||||||
|
And the ways
|
||||||
|
| nodes | oneway |
|
||||||
|
| abcd | no |
|
||||||
|
|
||||||
|
Given the query options
|
||||||
|
| waypoints | 0;2;3 |
|
||||||
|
|
||||||
|
When I match I should get
|
||||||
|
| trace | timestamps | code |
|
||||||
|
| ab1d | 0 1 2 3 | NoMatch |
|
||||||
|
|
||||||
|
Scenario: Regression test - avoid collapsing legs of a tidied split trace
|
||||||
|
Given a grid size of 20 meters
|
||||||
|
Given the node map
|
||||||
|
"""
|
||||||
|
a--b--f
|
||||||
|
|
|
||||||
|
|
|
||||||
|
e--c---d--g
|
||||||
|
"""
|
||||||
|
Given the query options
|
||||||
|
| tidy | true |
|
||||||
|
|
||||||
|
And the ways
|
||||||
|
| nodes | oneway |
|
||||||
|
| abf | no |
|
||||||
|
| be | no |
|
||||||
|
| ecdg | no |
|
||||||
|
|
||||||
|
When I match I should get
|
||||||
|
| trace | timestamps | matchings | code |
|
||||||
|
| abbecd | 10 11 27 1516914902 1516914913 1516914952 | ab,ecd | Ok |
|
||||||
|
|
||||||
|
|||||||
@@ -69,6 +69,11 @@ inline auto contractExcludableGraph(ContractorGraph contractor_graph_,
|
|||||||
});
|
});
|
||||||
non_core_edges.resize(new_end - non_core_edges.begin());
|
non_core_edges.resize(new_end - non_core_edges.begin());
|
||||||
edge_container.Insert(std::move(non_core_edges));
|
edge_container.Insert(std::move(non_core_edges));
|
||||||
|
|
||||||
|
for (const auto filter_index : util::irange<std::size_t>(0, filters.size()))
|
||||||
|
{
|
||||||
|
edge_container.Filter(filters[filter_index], filter_index);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// Extract core graph for further contraction
|
// Extract core graph for further contraction
|
||||||
|
|||||||
@@ -60,6 +60,25 @@ struct ContractedEdgeContainer
|
|||||||
flags.resize(edges.size(), ALL_FLAGS);
|
flags.resize(edges.size(), ALL_FLAGS);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void Filter(const std::vector<bool> &filter, std::size_t index)
|
||||||
|
{
|
||||||
|
BOOST_ASSERT(index < sizeof(MergedFlags) * CHAR_BIT);
|
||||||
|
const MergedFlags flag = 1 << index;
|
||||||
|
|
||||||
|
for (auto edge_index : util::irange<std::size_t>(0, edges.size()))
|
||||||
|
{
|
||||||
|
auto allowed = filter[edges[edge_index].source] && filter[edges[edge_index].target];
|
||||||
|
if (allowed)
|
||||||
|
{
|
||||||
|
flags[edge_index] |= flag;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
flags[edge_index] &= ~flag;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
void Merge(std::vector<QueryEdge> new_edges)
|
void Merge(std::vector<QueryEdge> new_edges)
|
||||||
{
|
{
|
||||||
BOOST_ASSERT(index < sizeof(MergedFlags) * CHAR_BIT);
|
BOOST_ASSERT(index < sizeof(MergedFlags) * CHAR_BIT);
|
||||||
|
|||||||
@@ -6,6 +6,7 @@
|
|||||||
#include "util/query_heap.hpp"
|
#include "util/query_heap.hpp"
|
||||||
|
|
||||||
#include <tbb/enumerable_thread_specific.h>
|
#include <tbb/enumerable_thread_specific.h>
|
||||||
|
#include <tbb/parallel_for.h>
|
||||||
|
|
||||||
#include <unordered_set>
|
#include <unordered_set>
|
||||||
|
|
||||||
|
|||||||
@@ -86,6 +86,10 @@ class MatchAPI final : public RouteAPI
|
|||||||
for (auto point_index : util::irange(
|
for (auto point_index : util::irange(
|
||||||
0u, static_cast<unsigned>(sub_matchings[sub_matching_index].indices.size())))
|
0u, static_cast<unsigned>(sub_matchings[sub_matching_index].indices.size())))
|
||||||
{
|
{
|
||||||
|
// tidied_to_original: index of the input coordinate that a tidied coordinate
|
||||||
|
// corresponds to.
|
||||||
|
// sub_matching indices: index of the coordinate passed to map matching plugin that
|
||||||
|
// a matched node corresponds to.
|
||||||
trace_idx_to_matching_idx[tidy_result
|
trace_idx_to_matching_idx[tidy_result
|
||||||
.tidied_to_original[sub_matchings[sub_matching_index]
|
.tidied_to_original[sub_matchings[sub_matching_index]
|
||||||
.indices[point_index]]] =
|
.indices[point_index]]] =
|
||||||
@@ -93,6 +97,9 @@ class MatchAPI final : public RouteAPI
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
BOOST_ASSERT(parameters.waypoints.empty() || sub_matchings.size() == 1);
|
||||||
|
|
||||||
|
std::size_t was_waypoint_idx = 0;
|
||||||
for (auto trace_index : util::irange<std::size_t>(0UL, parameters.coordinates.size()))
|
for (auto trace_index : util::irange<std::size_t>(0UL, parameters.coordinates.size()))
|
||||||
{
|
{
|
||||||
if (tidy_result.can_be_removed[trace_index])
|
if (tidy_result.can_be_removed[trace_index])
|
||||||
@@ -114,6 +121,20 @@ class MatchAPI final : public RouteAPI
|
|||||||
waypoint.values["alternatives_count"] =
|
waypoint.values["alternatives_count"] =
|
||||||
sub_matchings[matching_index.sub_matching_index]
|
sub_matchings[matching_index.sub_matching_index]
|
||||||
.alternatives_count[matching_index.point_index];
|
.alternatives_count[matching_index.point_index];
|
||||||
|
// waypoint indices need to be adjusted if route legs were collapsed
|
||||||
|
// waypoint parameter assumes there is only one match object
|
||||||
|
if (!parameters.waypoints.empty())
|
||||||
|
{
|
||||||
|
if (tidy_result.was_waypoint[trace_index])
|
||||||
|
{
|
||||||
|
waypoint.values["waypoint_index"] = was_waypoint_idx;
|
||||||
|
was_waypoint_idx++;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
waypoint.values["waypoint_index"] = util::json::Null();
|
||||||
|
}
|
||||||
|
}
|
||||||
waypoints.values.push_back(std::move(waypoint));
|
waypoints.values.push_back(std::move(waypoint));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -63,25 +63,40 @@ struct MatchParameters : public RouteParameters
|
|||||||
RouteParameters::GeometriesType::Polyline,
|
RouteParameters::GeometriesType::Polyline,
|
||||||
RouteParameters::OverviewType::Simplified,
|
RouteParameters::OverviewType::Simplified,
|
||||||
{}),
|
{}),
|
||||||
gaps(GapsType::Split), tidy(false)
|
gaps(GapsType::Split), tidy(false), waypoints()
|
||||||
{
|
{
|
||||||
}
|
}
|
||||||
|
|
||||||
template <typename... Args>
|
template <typename... Args>
|
||||||
MatchParameters(std::vector<unsigned> timestamps_, GapsType gaps_, bool tidy_, Args... args_)
|
MatchParameters(std::vector<unsigned> timestamps_, GapsType gaps_, bool tidy_, Args... args_)
|
||||||
|
: MatchParameters(std::move(timestamps_), gaps_, tidy_, {}, std::forward<Args>(args_)...)
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
|
template <typename... Args>
|
||||||
|
MatchParameters(std::vector<unsigned> timestamps_,
|
||||||
|
GapsType gaps_,
|
||||||
|
bool tidy_,
|
||||||
|
std::vector<std::size_t> waypoints_,
|
||||||
|
Args... args_)
|
||||||
: RouteParameters{std::forward<Args>(args_)...}, timestamps{std::move(timestamps_)},
|
: RouteParameters{std::forward<Args>(args_)...}, timestamps{std::move(timestamps_)},
|
||||||
gaps(gaps_), tidy(tidy_)
|
gaps(gaps_), tidy(tidy_), waypoints{std::move(waypoints_)}
|
||||||
{
|
{
|
||||||
}
|
}
|
||||||
|
|
||||||
std::vector<unsigned> timestamps;
|
std::vector<unsigned> timestamps;
|
||||||
GapsType gaps;
|
GapsType gaps;
|
||||||
bool tidy;
|
bool tidy;
|
||||||
|
std::vector<std::size_t> waypoints;
|
||||||
|
|
||||||
bool IsValid() const
|
bool IsValid() const
|
||||||
{
|
{
|
||||||
|
const auto valid_waypoints =
|
||||||
|
std::all_of(waypoints.begin(), waypoints.end(), [this](const auto &w) {
|
||||||
|
return w < coordinates.size();
|
||||||
|
});
|
||||||
return RouteParameters::IsValid() &&
|
return RouteParameters::IsValid() &&
|
||||||
(timestamps.empty() || timestamps.size() == coordinates.size());
|
(timestamps.empty() || timestamps.size() == coordinates.size()) && valid_waypoints;
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -37,6 +37,9 @@ struct Result
|
|||||||
Mask can_be_removed;
|
Mask can_be_removed;
|
||||||
// Maps the MatchParameter's original items to items which should not be removed.
|
// Maps the MatchParameter's original items to items which should not be removed.
|
||||||
Mapping tidied_to_original;
|
Mapping tidied_to_original;
|
||||||
|
// Masking the MatchParameter coordinates for items whose indices were present in the
|
||||||
|
// `waypoints` parameter.
|
||||||
|
Mask was_waypoint;
|
||||||
};
|
};
|
||||||
|
|
||||||
inline Result keep_all(const MatchParameters ¶ms)
|
inline Result keep_all(const MatchParameters ¶ms)
|
||||||
@@ -44,6 +47,17 @@ inline Result keep_all(const MatchParameters ¶ms)
|
|||||||
Result result;
|
Result result;
|
||||||
|
|
||||||
result.can_be_removed.resize(params.coordinates.size(), false);
|
result.can_be_removed.resize(params.coordinates.size(), false);
|
||||||
|
result.was_waypoint.resize(params.coordinates.size(), true);
|
||||||
|
// by default all input coordinates are treated as waypoints
|
||||||
|
if (!params.waypoints.empty())
|
||||||
|
{
|
||||||
|
for (const auto p : params.waypoints)
|
||||||
|
{
|
||||||
|
result.was_waypoint.set(p, false);
|
||||||
|
}
|
||||||
|
// logic is a little funny, uses inversion to set the bitfield
|
||||||
|
result.was_waypoint.flip();
|
||||||
|
}
|
||||||
result.tidied_to_original.reserve(params.coordinates.size());
|
result.tidied_to_original.reserve(params.coordinates.size());
|
||||||
for (std::size_t current = 0; current < params.coordinates.size(); ++current)
|
for (std::size_t current = 0; current < params.coordinates.size(); ++current)
|
||||||
{
|
{
|
||||||
@@ -61,6 +75,8 @@ inline Result keep_all(const MatchParameters ¶ms)
|
|||||||
{
|
{
|
||||||
result.parameters.coordinates.push_back(params.coordinates[i]);
|
result.parameters.coordinates.push_back(params.coordinates[i]);
|
||||||
|
|
||||||
|
if (result.was_waypoint[i])
|
||||||
|
result.parameters.waypoints.push_back(result.parameters.coordinates.size() - 1);
|
||||||
if (!params.hints.empty())
|
if (!params.hints.empty())
|
||||||
result.parameters.hints.push_back(params.hints[i]);
|
result.parameters.hints.push_back(params.hints[i]);
|
||||||
|
|
||||||
@@ -74,6 +90,8 @@ inline Result keep_all(const MatchParameters ¶ms)
|
|||||||
result.parameters.timestamps.push_back(params.timestamps[i]);
|
result.parameters.timestamps.push_back(params.timestamps[i]);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
if (params.waypoints.empty())
|
||||||
|
result.parameters.waypoints.clear();
|
||||||
|
|
||||||
return result;
|
return result;
|
||||||
}
|
}
|
||||||
@@ -85,6 +103,15 @@ inline Result tidy(const MatchParameters ¶ms, Thresholds cfg = {15., 5})
|
|||||||
Result result;
|
Result result;
|
||||||
|
|
||||||
result.can_be_removed.resize(params.coordinates.size(), false);
|
result.can_be_removed.resize(params.coordinates.size(), false);
|
||||||
|
result.was_waypoint.resize(params.coordinates.size(), true);
|
||||||
|
if (!params.waypoints.empty())
|
||||||
|
{
|
||||||
|
for (const auto p : params.waypoints)
|
||||||
|
{
|
||||||
|
result.was_waypoint.set(p, false);
|
||||||
|
}
|
||||||
|
result.was_waypoint.flip();
|
||||||
|
}
|
||||||
|
|
||||||
result.tidied_to_original.push_back(0);
|
result.tidied_to_original.push_back(0);
|
||||||
|
|
||||||
@@ -138,13 +165,14 @@ inline Result tidy(const MatchParameters ¶ms, Thresholds cfg = {15., 5})
|
|||||||
|
|
||||||
// We have to filter parallel arrays that may be empty or the exact same size.
|
// We have to filter parallel arrays that may be empty or the exact same size.
|
||||||
// result.parameters contains an empty MatchParameters at this point: conditionally fill.
|
// result.parameters contains an empty MatchParameters at this point: conditionally fill.
|
||||||
|
|
||||||
for (std::size_t i = 0; i < result.can_be_removed.size(); ++i)
|
for (std::size_t i = 0; i < result.can_be_removed.size(); ++i)
|
||||||
{
|
{
|
||||||
if (!result.can_be_removed[i])
|
if (!result.can_be_removed[i])
|
||||||
{
|
{
|
||||||
result.parameters.coordinates.push_back(params.coordinates[i]);
|
result.parameters.coordinates.push_back(params.coordinates[i]);
|
||||||
|
|
||||||
|
if (result.was_waypoint[i])
|
||||||
|
result.parameters.waypoints.push_back(result.parameters.coordinates.size() - 1);
|
||||||
if (!params.hints.empty())
|
if (!params.hints.empty())
|
||||||
result.parameters.hints.push_back(params.hints[i]);
|
result.parameters.hints.push_back(params.hints[i]);
|
||||||
|
|
||||||
@@ -157,8 +185,17 @@ inline Result tidy(const MatchParameters ¶ms, Thresholds cfg = {15., 5})
|
|||||||
if (!params.timestamps.empty())
|
if (!params.timestamps.empty())
|
||||||
result.parameters.timestamps.push_back(params.timestamps[i]);
|
result.parameters.timestamps.push_back(params.timestamps[i]);
|
||||||
}
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
// one of the coordinates meant to be used as a waypoint was marked for removal
|
||||||
|
// update the original waypoint index to the new representative coordinate
|
||||||
|
const auto last_idx = result.parameters.coordinates.size() - 1;
|
||||||
|
if (result.was_waypoint[i] && (result.parameters.waypoints.back() != last_idx))
|
||||||
|
{
|
||||||
|
result.parameters.waypoints.push_back(last_idx);
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
BOOST_ASSERT(result.tidied_to_original.size() == result.parameters.coordinates.size());
|
|
||||||
|
|
||||||
return result;
|
return result;
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -88,11 +88,12 @@ class RouteAPI : public BaseAPI
|
|||||||
{
|
{
|
||||||
util::json::Array annotations_store;
|
util::json::Array annotations_store;
|
||||||
annotations_store.values.reserve(leg.annotations.size());
|
annotations_store.values.reserve(leg.annotations.size());
|
||||||
std::for_each(leg.annotations.begin(),
|
|
||||||
leg.annotations.end(),
|
for (const auto &step : leg.annotations)
|
||||||
[Get, &annotations_store](const auto &step) {
|
{
|
||||||
annotations_store.values.push_back(Get(step));
|
annotations_store.values.push_back(Get(step));
|
||||||
});
|
}
|
||||||
|
|
||||||
return annotations_store;
|
return annotations_store;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -255,10 +256,19 @@ class RouteAPI : public BaseAPI
|
|||||||
// AnnotationsType uses bit flags, & operator checks if a property is set
|
// AnnotationsType uses bit flags, & operator checks if a property is set
|
||||||
if (parameters.annotations_type & RouteParameters::AnnotationsType::Speed)
|
if (parameters.annotations_type & RouteParameters::AnnotationsType::Speed)
|
||||||
{
|
{
|
||||||
|
double prev_speed = 0;
|
||||||
annotation.values["speed"] = GetAnnotations(
|
annotation.values["speed"] = GetAnnotations(
|
||||||
leg_geometry, [](const guidance::LegGeometry::Annotation &anno) {
|
leg_geometry, [&prev_speed](const guidance::LegGeometry::Annotation &anno) {
|
||||||
auto val = std::round(anno.distance / anno.duration * 10.) / 10.;
|
if (anno.duration < std::numeric_limits<double>::min())
|
||||||
return util::json::clamp_float(val);
|
{
|
||||||
|
return prev_speed;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
auto speed = std::round(anno.distance / anno.duration * 10.) / 10.;
|
||||||
|
prev_speed = speed;
|
||||||
|
return util::json::clamp_float(speed);
|
||||||
|
}
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -293,11 +303,10 @@ class RouteAPI : public BaseAPI
|
|||||||
{
|
{
|
||||||
util::json::Array nodes;
|
util::json::Array nodes;
|
||||||
nodes.values.reserve(leg_geometry.osm_node_ids.size());
|
nodes.values.reserve(leg_geometry.osm_node_ids.size());
|
||||||
std::for_each(leg_geometry.osm_node_ids.begin(),
|
for (const auto node_id : leg_geometry.osm_node_ids)
|
||||||
leg_geometry.osm_node_ids.end(),
|
{
|
||||||
[this, &nodes](const OSMNodeID &node_id) {
|
nodes.values.push_back(static_cast<std::uint64_t>(node_id));
|
||||||
nodes.values.push_back(static_cast<std::uint64_t>(node_id));
|
}
|
||||||
});
|
|
||||||
annotation.values["nodes"] = std::move(nodes);
|
annotation.values["nodes"] = std::move(nodes);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -7,11 +7,11 @@
|
|||||||
|
|
||||||
#include "engine/phantom_node.hpp"
|
#include "engine/phantom_node.hpp"
|
||||||
|
|
||||||
#include "osrm/coordinate.hpp"
|
#include "util/coordinate.hpp"
|
||||||
|
|
||||||
#include "util/guidance/entry_class.hpp"
|
#include "util/guidance/entry_class.hpp"
|
||||||
#include "util/guidance/turn_bearing.hpp"
|
#include "util/guidance/turn_bearing.hpp"
|
||||||
#include "util/guidance/turn_lanes.hpp"
|
#include "util/guidance/turn_lanes.hpp"
|
||||||
|
#include "util/integer_range.hpp"
|
||||||
#include "util/typedefs.hpp"
|
#include "util/typedefs.hpp"
|
||||||
|
|
||||||
#include <vector>
|
#include <vector>
|
||||||
@@ -102,6 +102,58 @@ struct InternalManyRoutesResult
|
|||||||
|
|
||||||
std::vector<InternalRouteResult> routes;
|
std::vector<InternalRouteResult> routes;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
inline InternalRouteResult CollapseInternalRouteResult(const InternalRouteResult &leggy_result,
|
||||||
|
const std::vector<bool> &is_waypoint)
|
||||||
|
{
|
||||||
|
BOOST_ASSERT(leggy_result.is_valid());
|
||||||
|
BOOST_ASSERT(is_waypoint[0]); // first and last coords
|
||||||
|
BOOST_ASSERT(is_waypoint.back()); // should always be waypoints
|
||||||
|
// Nothing to collapse! return result as is
|
||||||
|
if (leggy_result.unpacked_path_segments.size() == 1)
|
||||||
|
return leggy_result;
|
||||||
|
|
||||||
|
BOOST_ASSERT(leggy_result.segment_end_coordinates.size() > 1);
|
||||||
|
|
||||||
|
InternalRouteResult collapsed;
|
||||||
|
collapsed.shortest_path_weight = leggy_result.shortest_path_weight;
|
||||||
|
for (auto i : util::irange<std::size_t>(0, leggy_result.unpacked_path_segments.size()))
|
||||||
|
{
|
||||||
|
if (is_waypoint[i])
|
||||||
|
{
|
||||||
|
// start another leg vector
|
||||||
|
collapsed.unpacked_path_segments.push_back(leggy_result.unpacked_path_segments[i]);
|
||||||
|
// save new phantom node pair
|
||||||
|
collapsed.segment_end_coordinates.push_back(leggy_result.segment_end_coordinates[i]);
|
||||||
|
// save data about phantom nodes
|
||||||
|
collapsed.source_traversed_in_reverse.push_back(
|
||||||
|
leggy_result.source_traversed_in_reverse[i]);
|
||||||
|
collapsed.target_traversed_in_reverse.push_back(
|
||||||
|
leggy_result.target_traversed_in_reverse[i]);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
// no new leg, collapse the next segment into the last leg
|
||||||
|
{
|
||||||
|
BOOST_ASSERT(!collapsed.unpacked_path_segments.empty());
|
||||||
|
auto &last_segment = collapsed.unpacked_path_segments.back();
|
||||||
|
// deduplicate last segment (needs to be checked for empty for the same node query edge
|
||||||
|
// case)
|
||||||
|
if (!last_segment.empty())
|
||||||
|
last_segment.pop_back();
|
||||||
|
// update target phantom node of leg
|
||||||
|
BOOST_ASSERT(!collapsed.segment_end_coordinates.empty());
|
||||||
|
collapsed.segment_end_coordinates.back().target_phantom =
|
||||||
|
leggy_result.segment_end_coordinates[i].target_phantom;
|
||||||
|
collapsed.target_traversed_in_reverse.back() =
|
||||||
|
leggy_result.target_traversed_in_reverse[i];
|
||||||
|
// copy path segments into current leg
|
||||||
|
last_segment.insert(last_segment.end(),
|
||||||
|
leggy_result.unpacked_path_segments[i].begin(),
|
||||||
|
leggy_result.unpacked_path_segments[i].end());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return collapsed;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -39,8 +39,8 @@ struct ExtractionTurn
|
|||||||
const bool is_left_hand_driving;
|
const bool is_left_hand_driving;
|
||||||
double weight;
|
double weight;
|
||||||
double duration;
|
double duration;
|
||||||
TravelMode source_mode;
|
const TravelMode source_mode;
|
||||||
TravelMode target_mode;
|
const TravelMode target_mode;
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -0,0 +1,27 @@
|
|||||||
|
#ifndef OSRM_EXTRACTOR_GUIDANCE_HAVE_IDENTICAL_NAMES_HPP_
|
||||||
|
#define OSRM_EXTRACTOR_GUIDANCE_HAVE_IDENTICAL_NAMES_HPP_
|
||||||
|
|
||||||
|
#include "extractor/guidance/constants.hpp"
|
||||||
|
#include "extractor/suffix_table.hpp"
|
||||||
|
#include "util/name_table.hpp"
|
||||||
|
|
||||||
|
namespace osrm
|
||||||
|
{
|
||||||
|
namespace extractor
|
||||||
|
{
|
||||||
|
namespace guidance
|
||||||
|
{
|
||||||
|
|
||||||
|
// check if two name ids can be seen as identical (in presence of refs/others)
|
||||||
|
// in our case this translates into no name announcement in either direction (lhs->rhs and
|
||||||
|
// rhs->lhs)
|
||||||
|
bool HaveIdenticalNames(const NameID lhs,
|
||||||
|
const NameID rhs,
|
||||||
|
const util::NameTable &name_table,
|
||||||
|
const SuffixTable &street_name_suffix_table);
|
||||||
|
|
||||||
|
} // namespace guidance
|
||||||
|
} // namespace extractor
|
||||||
|
} // namespace osrm
|
||||||
|
|
||||||
|
#endif /*OSRM_EXTRACTOR_GUIDANCE_HAVE_IDENTICAL_NAMES_HPP_*/
|
||||||
@@ -293,10 +293,11 @@ struct IntersectionView final : std::vector<IntersectionViewData>, //
|
|||||||
};
|
};
|
||||||
|
|
||||||
// `Intersection` is a relative view of an intersection by an incoming edge.
|
// `Intersection` is a relative view of an intersection by an incoming edge.
|
||||||
// `Intersection` are streets at an intersection ordered from from sharp right counter-clockwise to
|
// `Intersection` are streets at an intersection stored as an ordered list of connected roads
|
||||||
|
// ordered from sharp right counter-clockwise to
|
||||||
// sharp left where `intersection[0]` is _always_ a u-turn
|
// sharp left where `intersection[0]` is _always_ a u-turn
|
||||||
|
|
||||||
// An intersection is an ordered list of connected roads ordered from from sharp right
|
// An intersection is an ordered list of connected roads ordered from sharp right
|
||||||
// counter-clockwise to sharp left where `intersection[0]` is always a u-turn
|
// counter-clockwise to sharp left where `intersection[0]` is always a u-turn
|
||||||
//
|
//
|
||||||
// |
|
// |
|
||||||
|
|||||||
@@ -67,6 +67,8 @@ class IntersectionHandler
|
|||||||
// Decide on a basic turn types
|
// Decide on a basic turn types
|
||||||
TurnType::Enum findBasicTurnType(const EdgeID via_edge, const ConnectedRoad &candidate) const;
|
TurnType::Enum findBasicTurnType(const EdgeID via_edge, const ConnectedRoad &candidate) const;
|
||||||
|
|
||||||
|
TurnType::Enum areSameClasses(const EdgeID via_edge, const ConnectedRoad &road) const;
|
||||||
|
|
||||||
// Find the most obvious turn to follow. The function returns an index into the intersection
|
// Find the most obvious turn to follow. The function returns an index into the intersection
|
||||||
// determining whether there is a road that can be seen as obvious turn in the presence of many
|
// determining whether there is a road that can be seen as obvious turn in the presence of many
|
||||||
// other possible turns. The function will consider road categories and other inputs like the
|
// other possible turns. The function will consider road categories and other inputs like the
|
||||||
@@ -96,9 +98,6 @@ class IntersectionHandler
|
|||||||
const std::size_t begin,
|
const std::size_t begin,
|
||||||
const std::size_t end) const;
|
const std::size_t end) const;
|
||||||
|
|
||||||
// Checks the intersection for a through street connected to `intersection[index]`
|
|
||||||
bool isThroughStreet(const std::size_t index, const Intersection &intersection) const;
|
|
||||||
|
|
||||||
// See `getNextIntersection`
|
// See `getNextIntersection`
|
||||||
struct IntersectionViewAndNode final
|
struct IntersectionViewAndNode final
|
||||||
{
|
{
|
||||||
|
|||||||
@@ -0,0 +1,63 @@
|
|||||||
|
#ifndef OSRM_EXTRACTOR_GUIDANCE_IS_THROUGH_STREET_HPP_
|
||||||
|
#define OSRM_EXTRACTOR_GUIDANCE_IS_THROUGH_STREET_HPP_
|
||||||
|
|
||||||
|
#include "extractor/guidance/constants.hpp"
|
||||||
|
#include "extractor/suffix_table.hpp"
|
||||||
|
#include "util/guidance/name_announcements.hpp"
|
||||||
|
|
||||||
|
using osrm::util::angularDeviation;
|
||||||
|
|
||||||
|
namespace osrm
|
||||||
|
{
|
||||||
|
namespace extractor
|
||||||
|
{
|
||||||
|
namespace guidance
|
||||||
|
{
|
||||||
|
|
||||||
|
template <typename IntersectionType>
|
||||||
|
inline bool isThroughStreet(const std::size_t index,
|
||||||
|
const IntersectionType &intersection,
|
||||||
|
const util::NodeBasedDynamicGraph &node_based_graph,
|
||||||
|
const EdgeBasedNodeDataContainer &node_data_container,
|
||||||
|
const util::NameTable &name_table,
|
||||||
|
const SuffixTable &street_name_suffix_table)
|
||||||
|
{
|
||||||
|
|
||||||
|
const auto &data_at_index = node_data_container.GetAnnotation(
|
||||||
|
node_based_graph.GetEdgeData(intersection[index].eid).annotation_data);
|
||||||
|
|
||||||
|
if (data_at_index.name_id == EMPTY_NAMEID)
|
||||||
|
return false;
|
||||||
|
|
||||||
|
// a through street cannot start at our own position -> index 1
|
||||||
|
for (std::size_t road_index = 1; road_index < intersection.size(); ++road_index)
|
||||||
|
{
|
||||||
|
if (road_index == index)
|
||||||
|
continue;
|
||||||
|
|
||||||
|
const auto &road = intersection[road_index];
|
||||||
|
const auto &road_data = node_data_container.GetAnnotation(
|
||||||
|
node_based_graph.GetEdgeData(road.eid).annotation_data);
|
||||||
|
|
||||||
|
// roads have a near straight angle (180 degree)
|
||||||
|
const bool is_nearly_straight = angularDeviation(road.angle, intersection[index].angle) >
|
||||||
|
(STRAIGHT_ANGLE - FUZZY_ANGLE_DIFFERENCE);
|
||||||
|
|
||||||
|
const bool have_same_name = HaveIdenticalNames(
|
||||||
|
data_at_index.name_id, road_data.name_id, name_table, street_name_suffix_table);
|
||||||
|
|
||||||
|
const bool have_same_category =
|
||||||
|
node_based_graph.GetEdgeData(intersection[index].eid).flags.road_classification ==
|
||||||
|
node_based_graph.GetEdgeData(road.eid).flags.road_classification;
|
||||||
|
|
||||||
|
if (is_nearly_straight && have_same_name && have_same_category)
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
} // namespace guidance
|
||||||
|
} // namespace extractor
|
||||||
|
} // namespace osrm
|
||||||
|
|
||||||
|
#endif /*OSRM_EXTRACTOR_GUIDANCE_IS_THROUGH_STREET_HPP_*/
|
||||||
@@ -3,6 +3,7 @@
|
|||||||
|
|
||||||
#include "extractor/compressed_edge_container.hpp"
|
#include "extractor/compressed_edge_container.hpp"
|
||||||
#include "extractor/guidance/coordinate_extractor.hpp"
|
#include "extractor/guidance/coordinate_extractor.hpp"
|
||||||
|
#include "extractor/guidance/have_identical_names.hpp"
|
||||||
#include "extractor/guidance/intersection.hpp"
|
#include "extractor/guidance/intersection.hpp"
|
||||||
#include "extractor/guidance/turn_lane_types.hpp"
|
#include "extractor/guidance/turn_lane_types.hpp"
|
||||||
#include "extractor/restriction_index.hpp"
|
#include "extractor/restriction_index.hpp"
|
||||||
@@ -78,11 +79,6 @@ class MergableRoadDetector
|
|||||||
bool IsDistinctFrom(const MergableRoadData &lhs, const MergableRoadData &rhs) const;
|
bool IsDistinctFrom(const MergableRoadData &lhs, const MergableRoadData &rhs) const;
|
||||||
|
|
||||||
private:
|
private:
|
||||||
// check if two name ids can be seen as identical (in presence of refs/others)
|
|
||||||
// in our case this translates into no name announcement in either direction (lhs->rhs and
|
|
||||||
// rhs->lhs)
|
|
||||||
bool HaveIdenticalNames(const NameID lhs, const NameID rhs) const;
|
|
||||||
|
|
||||||
// When it comes to merging roads, we need to find out if two ways actually represent the
|
// When it comes to merging roads, we need to find out if two ways actually represent the
|
||||||
// same road. This check tries to identify roads which are the same road in opposite directions
|
// same road. This check tries to identify roads which are the same road in opposite directions
|
||||||
bool EdgeDataSupportsMerge(const NodeBasedEdgeClassification &lhs_flags,
|
bool EdgeDataSupportsMerge(const NodeBasedEdgeClassification &lhs_flags,
|
||||||
|
|||||||
@@ -3,6 +3,7 @@
|
|||||||
|
|
||||||
#include "extractor/guidance/intersection.hpp"
|
#include "extractor/guidance/intersection.hpp"
|
||||||
#include "extractor/guidance/intersection_handler.hpp"
|
#include "extractor/guidance/intersection_handler.hpp"
|
||||||
|
#include "extractor/guidance/is_through_street.hpp"
|
||||||
#include "extractor/query_node.hpp"
|
#include "extractor/query_node.hpp"
|
||||||
|
|
||||||
#include "util/attributes.hpp"
|
#include "util/attributes.hpp"
|
||||||
|
|||||||
@@ -5,6 +5,7 @@
|
|||||||
#include "extractor/guidance/coordinate_extractor.hpp"
|
#include "extractor/guidance/coordinate_extractor.hpp"
|
||||||
#include "extractor/guidance/intersection.hpp"
|
#include "extractor/guidance/intersection.hpp"
|
||||||
#include "extractor/guidance/intersection_handler.hpp"
|
#include "extractor/guidance/intersection_handler.hpp"
|
||||||
|
#include "extractor/guidance/is_through_street.hpp"
|
||||||
#include "extractor/guidance/roundabout_type.hpp"
|
#include "extractor/guidance/roundabout_type.hpp"
|
||||||
#include "extractor/query_node.hpp"
|
#include "extractor/query_node.hpp"
|
||||||
|
|
||||||
|
|||||||
@@ -3,6 +3,7 @@
|
|||||||
|
|
||||||
#include "extractor/guidance/intersection.hpp"
|
#include "extractor/guidance/intersection.hpp"
|
||||||
#include "extractor/guidance/intersection_handler.hpp"
|
#include "extractor/guidance/intersection_handler.hpp"
|
||||||
|
#include "extractor/guidance/is_through_street.hpp"
|
||||||
#include "extractor/query_node.hpp"
|
#include "extractor/query_node.hpp"
|
||||||
|
|
||||||
#include "util/name_table.hpp"
|
#include "util/name_table.hpp"
|
||||||
@@ -53,9 +54,6 @@ class SliproadHandler final : public IntersectionHandler
|
|||||||
// Next intersection from `start` onto `onto` is too far away for a Siproad scenario
|
// Next intersection from `start` onto `onto` is too far away for a Siproad scenario
|
||||||
bool nextIntersectionIsTooFarAway(const NodeID start, const EdgeID onto) const;
|
bool nextIntersectionIsTooFarAway(const NodeID start, const EdgeID onto) const;
|
||||||
|
|
||||||
// Through street: does a road continue with from's name at the intersection
|
|
||||||
bool isThroughStreet(const EdgeID from, const IntersectionView &intersection) const;
|
|
||||||
|
|
||||||
// Does the road from `current` to `next` continue
|
// Does the road from `current` to `next` continue
|
||||||
bool roadContinues(const EdgeID current, const EdgeID next) const;
|
bool roadContinues(const EdgeID current, const EdgeID next) const;
|
||||||
|
|
||||||
|
|||||||
@@ -12,7 +12,7 @@ namespace osrm
|
|||||||
{
|
{
|
||||||
namespace util
|
namespace util
|
||||||
{
|
{
|
||||||
class Coordinate;
|
struct Coordinate;
|
||||||
}
|
}
|
||||||
|
|
||||||
namespace extractor
|
namespace extractor
|
||||||
|
|||||||
@@ -3,6 +3,7 @@
|
|||||||
|
|
||||||
#include "extractor/guidance/intersection.hpp"
|
#include "extractor/guidance/intersection.hpp"
|
||||||
#include "extractor/guidance/intersection_handler.hpp"
|
#include "extractor/guidance/intersection_handler.hpp"
|
||||||
|
#include "extractor/guidance/is_through_street.hpp"
|
||||||
#include "extractor/query_node.hpp"
|
#include "extractor/query_node.hpp"
|
||||||
|
|
||||||
#include "util/attributes.hpp"
|
#include "util/attributes.hpp"
|
||||||
|
|||||||
@@ -10,8 +10,6 @@
|
|||||||
|
|
||||||
#include <boost/optional/optional.hpp>
|
#include <boost/optional/optional.hpp>
|
||||||
|
|
||||||
#include <tbb/concurrent_vector.h>
|
|
||||||
|
|
||||||
#include <string>
|
#include <string>
|
||||||
#include <vector>
|
#include <vector>
|
||||||
|
|
||||||
|
|||||||
@@ -1171,7 +1171,7 @@ argumentsToMatchParameter(const Nan::FunctionCallbackInfo<v8::Value> &args,
|
|||||||
Nan::ThrowError("Timestamps array items must be numbers");
|
Nan::ThrowError("Timestamps array items must be numbers");
|
||||||
return match_parameters_ptr();
|
return match_parameters_ptr();
|
||||||
}
|
}
|
||||||
params->timestamps.emplace_back(static_cast<unsigned>(timestamp->NumberValue()));
|
params->timestamps.emplace_back(static_cast<std::size_t>(timestamp->NumberValue()));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -1220,6 +1220,60 @@ argumentsToMatchParameter(const Nan::FunctionCallbackInfo<v8::Value> &args,
|
|||||||
params->tidy = tidy->BooleanValue();
|
params->tidy = tidy->BooleanValue();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (obj->Has(Nan::New("waypoints").ToLocalChecked()))
|
||||||
|
{
|
||||||
|
v8::Local<v8::Value> waypoints = obj->Get(Nan::New("waypoints").ToLocalChecked());
|
||||||
|
if (waypoints.IsEmpty())
|
||||||
|
return match_parameters_ptr();
|
||||||
|
|
||||||
|
// must be array
|
||||||
|
if (!waypoints->IsArray())
|
||||||
|
{
|
||||||
|
Nan::ThrowError(
|
||||||
|
"Waypoints must be an array of integers corresponding to the input coordinates.");
|
||||||
|
return match_parameters_ptr();
|
||||||
|
}
|
||||||
|
|
||||||
|
auto waypoints_array = v8::Local<v8::Array>::Cast(waypoints);
|
||||||
|
// must have at least two elements
|
||||||
|
if (waypoints_array->Length() < 2)
|
||||||
|
{
|
||||||
|
Nan::ThrowError("At least two waypoints must be provided");
|
||||||
|
return match_parameters_ptr();
|
||||||
|
}
|
||||||
|
auto coords_size = params->coordinates.size();
|
||||||
|
auto waypoints_array_size = waypoints_array->Length();
|
||||||
|
|
||||||
|
const auto first_index = Nan::To<std::uint32_t>(waypoints_array->Get(0)).FromJust();
|
||||||
|
const auto last_index =
|
||||||
|
Nan::To<std::uint32_t>(waypoints_array->Get(waypoints_array_size - 1)).FromJust();
|
||||||
|
if (first_index != 0 || last_index != coords_size - 1)
|
||||||
|
{
|
||||||
|
Nan::ThrowError("First and last waypoints values must correspond to first and last "
|
||||||
|
"coordinate indices");
|
||||||
|
return match_parameters_ptr();
|
||||||
|
}
|
||||||
|
|
||||||
|
for (uint32_t i = 0; i < waypoints_array_size; ++i)
|
||||||
|
{
|
||||||
|
v8::Local<v8::Value> waypoint_value = waypoints_array->Get(i);
|
||||||
|
// all elements must be numbers
|
||||||
|
if (!waypoint_value->IsNumber())
|
||||||
|
{
|
||||||
|
Nan::ThrowError("Waypoint values must be an array of integers");
|
||||||
|
return match_parameters_ptr();
|
||||||
|
}
|
||||||
|
// check that the waypoint index corresponds with an inpute coordinate
|
||||||
|
const auto index = Nan::To<std::uint32_t>(waypoint_value).FromJust();
|
||||||
|
if (index >= coords_size)
|
||||||
|
{
|
||||||
|
Nan::ThrowError("Waypoints must correspond with the index of an input coordinate");
|
||||||
|
return match_parameters_ptr();
|
||||||
|
}
|
||||||
|
params->waypoints.emplace_back(static_cast<unsigned>(waypoint_value->NumberValue()));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
bool parsedSuccessfully = parseCommonParameters(obj, params);
|
bool parsedSuccessfully = parseCommonParameters(obj, params);
|
||||||
if (!parsedSuccessfully)
|
if (!parsedSuccessfully)
|
||||||
{
|
{
|
||||||
|
|||||||
@@ -16,6 +16,7 @@
|
|||||||
|
|
||||||
#include <boost/iterator/iterator_facade.hpp>
|
#include <boost/iterator/iterator_facade.hpp>
|
||||||
#include <boost/range/iterator_range.hpp>
|
#include <boost/range/iterator_range.hpp>
|
||||||
|
|
||||||
#include <tbb/parallel_sort.h>
|
#include <tbb/parallel_sort.h>
|
||||||
|
|
||||||
#include <algorithm>
|
#include <algorithm>
|
||||||
|
|||||||
@@ -10,8 +10,9 @@
|
|||||||
#include "util/dynamic_graph.hpp"
|
#include "util/dynamic_graph.hpp"
|
||||||
#include "util/typedefs.hpp"
|
#include "util/typedefs.hpp"
|
||||||
|
|
||||||
|
#include <tbb/blocked_range.h>
|
||||||
|
#include <tbb/parallel_for.h>
|
||||||
#include <tbb/parallel_reduce.h>
|
#include <tbb/parallel_reduce.h>
|
||||||
#include <tbb/parallel_sort.h>
|
|
||||||
|
|
||||||
#include <cstdint>
|
#include <cstdint>
|
||||||
|
|
||||||
|
|||||||
@@ -28,17 +28,31 @@ struct MatchParametersGrammar final : public RouteParametersGrammar<Iterator, Si
|
|||||||
|
|
||||||
MatchParametersGrammar() : BaseGrammar(root_rule)
|
MatchParametersGrammar() : BaseGrammar(root_rule)
|
||||||
{
|
{
|
||||||
|
#ifdef BOOST_HAS_LONG_LONG
|
||||||
|
if (std::is_same<std::size_t, unsigned long long>::value)
|
||||||
|
size_t_ = qi::ulong_long;
|
||||||
|
else
|
||||||
|
size_t_ = qi::ulong_;
|
||||||
|
#else
|
||||||
|
size_t_ = qi::ulong_;
|
||||||
|
#endif
|
||||||
|
|
||||||
timestamps_rule =
|
timestamps_rule =
|
||||||
qi::lit("timestamps=") >
|
qi::lit("timestamps=") >
|
||||||
(qi::uint_ %
|
(qi::uint_ %
|
||||||
';')[ph::bind(&engine::api::MatchParameters::timestamps, qi::_r1) = qi::_1];
|
';')[ph::bind(&engine::api::MatchParameters::timestamps, qi::_r1) = qi::_1];
|
||||||
|
|
||||||
|
waypoints_rule =
|
||||||
|
qi::lit("waypoints=") >
|
||||||
|
(size_t_ % ';')[ph::bind(&engine::api::MatchParameters::waypoints, qi::_r1) = qi::_1];
|
||||||
|
|
||||||
gaps_type.add("split", engine::api::MatchParameters::GapsType::Split)(
|
gaps_type.add("split", engine::api::MatchParameters::GapsType::Split)(
|
||||||
"ignore", engine::api::MatchParameters::GapsType::Ignore);
|
"ignore", engine::api::MatchParameters::GapsType::Ignore);
|
||||||
|
|
||||||
root_rule =
|
root_rule =
|
||||||
BaseGrammar::query_rule(qi::_r1) > -qi::lit(".json") >
|
BaseGrammar::query_rule(qi::_r1) > -qi::lit(".json") >
|
||||||
-('?' > (timestamps_rule(qi::_r1) | BaseGrammar::base_rule(qi::_r1) |
|
-('?' > (timestamps_rule(qi::_r1) | BaseGrammar::base_rule(qi::_r1) |
|
||||||
|
waypoints_rule(qi::_r1) |
|
||||||
(qi::lit("gaps=") >
|
(qi::lit("gaps=") >
|
||||||
gaps_type[ph::bind(&engine::api::MatchParameters::gaps, qi::_r1) = qi::_1]) |
|
gaps_type[ph::bind(&engine::api::MatchParameters::gaps, qi::_r1) = qi::_1]) |
|
||||||
(qi::lit("tidy=") >
|
(qi::lit("tidy=") >
|
||||||
@@ -49,6 +63,8 @@ struct MatchParametersGrammar final : public RouteParametersGrammar<Iterator, Si
|
|||||||
private:
|
private:
|
||||||
qi::rule<Iterator, Signature> root_rule;
|
qi::rule<Iterator, Signature> root_rule;
|
||||||
qi::rule<Iterator, Signature> timestamps_rule;
|
qi::rule<Iterator, Signature> timestamps_rule;
|
||||||
|
qi::rule<Iterator, Signature> waypoints_rule;
|
||||||
|
qi::rule<Iterator, std::size_t()> size_t_;
|
||||||
|
|
||||||
qi::symbols<char, engine::api::MatchParameters::GapsType> gaps_type;
|
qi::symbols<char, engine::api::MatchParameters::GapsType> gaps_type;
|
||||||
};
|
};
|
||||||
|
|||||||
@@ -10,6 +10,7 @@
|
|||||||
|
|
||||||
#include <boost/iterator/iterator_facade.hpp>
|
#include <boost/iterator/iterator_facade.hpp>
|
||||||
#include <boost/iterator/reverse_iterator.hpp>
|
#include <boost/iterator/reverse_iterator.hpp>
|
||||||
|
|
||||||
#include <tbb/atomic.h>
|
#include <tbb/atomic.h>
|
||||||
|
|
||||||
#include <array>
|
#include <array>
|
||||||
|
|||||||
@@ -23,6 +23,7 @@
|
|||||||
#include <boost/format.hpp>
|
#include <boost/format.hpp>
|
||||||
#include <boost/iostreams/device/mapped_file.hpp>
|
#include <boost/iostreams/device/mapped_file.hpp>
|
||||||
|
|
||||||
|
#include <tbb/blocked_range.h>
|
||||||
#include <tbb/parallel_for.h>
|
#include <tbb/parallel_for.h>
|
||||||
#include <tbb/parallel_sort.h>
|
#include <tbb/parallel_sort.h>
|
||||||
|
|
||||||
|
|||||||
+1
-1
@@ -1,6 +1,6 @@
|
|||||||
{
|
{
|
||||||
"name": "osrm",
|
"name": "osrm",
|
||||||
"version": "5.15.0-latest.4",
|
"version": "5.15.2",
|
||||||
"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": {
|
||||||
|
|||||||
+1
-1
@@ -104,7 +104,7 @@ function setup()
|
|||||||
},
|
},
|
||||||
|
|
||||||
classes = Sequence {
|
classes = Sequence {
|
||||||
'toll', 'motorway', 'ferry', 'restricted'
|
'toll', 'motorway', 'ferry', 'restricted', 'tunnel'
|
||||||
},
|
},
|
||||||
|
|
||||||
-- classes to support for exclude flags
|
-- classes to support for exclude flags
|
||||||
|
|||||||
@@ -23,8 +23,6 @@ function Measure.parse_value_meters(value)
|
|||||||
end
|
end
|
||||||
return n
|
return n
|
||||||
end
|
end
|
||||||
|
|
||||||
print("Can't parse value: ", value)
|
|
||||||
end
|
end
|
||||||
|
|
||||||
--- according to http://wiki.openstreetmap.org/wiki/Map_Features/Units#Explicit_specifications
|
--- according to http://wiki.openstreetmap.org/wiki/Map_Features/Units#Explicit_specifications
|
||||||
@@ -55,10 +53,6 @@ function Measure.parse_value_kilograms(value)
|
|||||||
return tonumber(m) * 1000
|
return tonumber(m) * 1000
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
--
|
|
||||||
print("Can't parse value: ", value)
|
|
||||||
return
|
|
||||||
end
|
end
|
||||||
|
|
||||||
--- Get maxheight of specified way in meters. If there are no
|
--- Get maxheight of specified way in meters. If there are no
|
||||||
|
|||||||
@@ -283,6 +283,12 @@ end
|
|||||||
function WayHandlers.classes(profile,way,result,data)
|
function WayHandlers.classes(profile,way,result,data)
|
||||||
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")
|
||||||
|
|
||||||
|
if tunnel and tunnel ~= "no" then
|
||||||
|
result.forward_classes["tunnel"] = true
|
||||||
|
result.backward_classes["tunnel"] = true
|
||||||
|
end
|
||||||
|
|
||||||
if forward_toll == "yes" then
|
if forward_toll == "yes" then
|
||||||
result.forward_classes["toll"] = true
|
result.forward_classes["toll"] = true
|
||||||
|
|||||||
@@ -12,6 +12,7 @@
|
|||||||
|
|
||||||
#include <boost/assert.hpp>
|
#include <boost/assert.hpp>
|
||||||
|
|
||||||
|
#include <tbb/blocked_range.h>
|
||||||
#include <tbb/enumerable_thread_specific.h>
|
#include <tbb/enumerable_thread_specific.h>
|
||||||
#include <tbb/parallel_for.h>
|
#include <tbb/parallel_for.h>
|
||||||
#include <tbb/parallel_invoke.h>
|
#include <tbb/parallel_invoke.h>
|
||||||
|
|||||||
@@ -17,6 +17,7 @@
|
|||||||
#include <functional>
|
#include <functional>
|
||||||
#include <iterator>
|
#include <iterator>
|
||||||
#include <memory>
|
#include <memory>
|
||||||
|
#include <set>
|
||||||
#include <string>
|
#include <string>
|
||||||
#include <vector>
|
#include <vector>
|
||||||
|
|
||||||
@@ -174,6 +175,16 @@ Status MatchPlugin::HandleRequest(const RoutingAlgorithmsInterface &algorithms,
|
|||||||
tidied = api::tidy::keep_all(parameters);
|
tidied = api::tidy::keep_all(parameters);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Error: first and last points should be waypoints
|
||||||
|
if (!parameters.waypoints.empty() &&
|
||||||
|
(tidied.parameters.waypoints[0] != 0 ||
|
||||||
|
tidied.parameters.waypoints.back() != (tidied.parameters.coordinates.size() - 1)))
|
||||||
|
{
|
||||||
|
return Error("InvalidValue",
|
||||||
|
"First and last coordinates must be specified as waypoints.",
|
||||||
|
json_result);
|
||||||
|
}
|
||||||
|
|
||||||
// assuming radius is the standard deviation of a normal distribution
|
// assuming radius is the standard deviation of a normal distribution
|
||||||
// that models GPS noise (in this model), x3 should give us the correct
|
// that models GPS noise (in this model), x3 should give us the correct
|
||||||
// search radius with > 99% confidence
|
// search radius with > 99% confidence
|
||||||
@@ -229,6 +240,34 @@ Status MatchPlugin::HandleRequest(const RoutingAlgorithmsInterface &algorithms,
|
|||||||
return Error("NoMatch", "Could not match the trace.", json_result);
|
return Error("NoMatch", "Could not match the trace.", json_result);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// trace was split, we don't support the waypoints parameter across multiple match objects
|
||||||
|
if (sub_matchings.size() > 1 && !parameters.waypoints.empty())
|
||||||
|
{
|
||||||
|
return Error("NoMatch", "Could not match the trace with the given waypoints.", json_result);
|
||||||
|
}
|
||||||
|
|
||||||
|
// Error: Check if user-supplied waypoints can be found in the resulting matches
|
||||||
|
if (!parameters.waypoints.empty())
|
||||||
|
{
|
||||||
|
std::set<std::size_t> tidied_waypoints(tidied.parameters.waypoints.begin(),
|
||||||
|
tidied.parameters.waypoints.end());
|
||||||
|
for (const auto &sm : sub_matchings)
|
||||||
|
{
|
||||||
|
std::for_each(sm.indices.begin(),
|
||||||
|
sm.indices.end(),
|
||||||
|
[&tidied_waypoints](const auto index) { tidied_waypoints.erase(index); });
|
||||||
|
}
|
||||||
|
if (!tidied_waypoints.empty())
|
||||||
|
{
|
||||||
|
return Error(
|
||||||
|
"NoMatch", "Requested waypoint parameter could not be matched.", json_result);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
// we haven't errored yet, only allow leg collapsing if it was originally requested
|
||||||
|
BOOST_ASSERT(parameters.waypoints.empty() || sub_matchings.size() == 1);
|
||||||
|
const auto collapse_legs = !parameters.waypoints.empty();
|
||||||
|
|
||||||
|
// each sub_route will correspond to a MatchObject
|
||||||
std::vector<InternalRouteResult> sub_routes(sub_matchings.size());
|
std::vector<InternalRouteResult> sub_routes(sub_matchings.size());
|
||||||
for (auto index : util::irange<std::size_t>(0UL, sub_matchings.size()))
|
for (auto index : util::irange<std::size_t>(0UL, sub_matchings.size()))
|
||||||
{
|
{
|
||||||
@@ -245,12 +284,31 @@ Status MatchPlugin::HandleRequest(const RoutingAlgorithmsInterface &algorithms,
|
|||||||
BOOST_ASSERT(current_phantom_node_pair.target_phantom.IsValid());
|
BOOST_ASSERT(current_phantom_node_pair.target_phantom.IsValid());
|
||||||
sub_routes[index].segment_end_coordinates.emplace_back(current_phantom_node_pair);
|
sub_routes[index].segment_end_coordinates.emplace_back(current_phantom_node_pair);
|
||||||
}
|
}
|
||||||
// force uturns to be on, since we split the phantom nodes anyway and only have
|
// force uturns to be on
|
||||||
// bi-directional
|
// we split the phantom nodes anyway and only have bi-directional phantom nodes for
|
||||||
// phantom nodes for possible uturns
|
// possible uturns
|
||||||
sub_routes[index] =
|
sub_routes[index] =
|
||||||
algorithms.ShortestPathSearch(sub_routes[index].segment_end_coordinates, {false});
|
algorithms.ShortestPathSearch(sub_routes[index].segment_end_coordinates, {false});
|
||||||
BOOST_ASSERT(sub_routes[index].shortest_path_weight != INVALID_EDGE_WEIGHT);
|
BOOST_ASSERT(sub_routes[index].shortest_path_weight != INVALID_EDGE_WEIGHT);
|
||||||
|
if (collapse_legs)
|
||||||
|
{
|
||||||
|
std::vector<bool> waypoint_legs;
|
||||||
|
waypoint_legs.reserve(sub_matchings[index].indices.size());
|
||||||
|
for (unsigned i = 0, j = 0; i < sub_matchings[index].indices.size(); ++i)
|
||||||
|
{
|
||||||
|
auto current_wp = tidied.parameters.waypoints[j];
|
||||||
|
if (current_wp == sub_matchings[index].indices[i])
|
||||||
|
{
|
||||||
|
waypoint_legs.push_back(true);
|
||||||
|
++j;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
waypoint_legs.push_back(false);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
sub_routes[index] = CollapseInternalRouteResult(sub_routes[index], waypoint_legs);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
api::MatchAPI match_api{facade, parameters, tidied};
|
api::MatchAPI match_api{facade, parameters, tidied};
|
||||||
|
|||||||
@@ -365,7 +365,7 @@ Extractor::ParseOSMData(ScriptingEnvironment &scripting_environment,
|
|||||||
TIMER_START(parsing);
|
TIMER_START(parsing);
|
||||||
|
|
||||||
{ // Parse OSM header
|
{ // Parse OSM header
|
||||||
osmium::io::Reader reader(input_file, osmium::osm_entity_bits::nothing);
|
osmium::io::Reader reader(input_file, pool, osmium::osm_entity_bits::nothing);
|
||||||
osmium::io::Header header = reader.header();
|
osmium::io::Header header = reader.header();
|
||||||
|
|
||||||
std::string generator = header.get("generator");
|
std::string generator = header.get("generator");
|
||||||
@@ -545,7 +545,7 @@ Extractor::ParseOSMData(ScriptingEnvironment &scripting_environment,
|
|||||||
|
|
||||||
{ // Relations reading pipeline
|
{ // Relations reading pipeline
|
||||||
util::Log() << "Parse relations ...";
|
util::Log() << "Parse relations ...";
|
||||||
osmium::io::Reader reader(input_file, osmium::osm_entity_bits::relation, read_meta);
|
osmium::io::Reader reader(input_file, pool, osmium::osm_entity_bits::relation, read_meta);
|
||||||
tbb::parallel_pipeline(
|
tbb::parallel_pipeline(
|
||||||
num_threads, buffer_reader(reader) & buffer_relation_cache & buffer_storage_relation);
|
num_threads, buffer_reader(reader) & buffer_relation_cache & buffer_storage_relation);
|
||||||
}
|
}
|
||||||
@@ -553,6 +553,7 @@ Extractor::ParseOSMData(ScriptingEnvironment &scripting_environment,
|
|||||||
{ // Nodes and ways reading pipeline
|
{ // Nodes and ways reading pipeline
|
||||||
util::Log() << "Parse ways and nodes ...";
|
util::Log() << "Parse ways and nodes ...";
|
||||||
osmium::io::Reader reader(input_file,
|
osmium::io::Reader reader(input_file,
|
||||||
|
pool,
|
||||||
osmium::osm_entity_bits::node | osmium::osm_entity_bits::way |
|
osmium::osm_entity_bits::node | osmium::osm_entity_bits::way |
|
||||||
osmium::osm_entity_bits::relation,
|
osmium::osm_entity_bits::relation,
|
||||||
read_meta);
|
read_meta);
|
||||||
|
|||||||
@@ -0,0 +1,33 @@
|
|||||||
|
#ifndef OSRM_EXTRACTOR_GUIDANCE_HAVE_IDENTICAL_NAMES_HPP_
|
||||||
|
#define OSRM_EXTRACTOR_GUIDANCE_HAVE_IDENTICAL_NAMES_HPP_
|
||||||
|
|
||||||
|
#include "util/guidance/name_announcements.hpp"
|
||||||
|
|
||||||
|
namespace osrm
|
||||||
|
{
|
||||||
|
namespace extractor
|
||||||
|
{
|
||||||
|
namespace guidance
|
||||||
|
{
|
||||||
|
|
||||||
|
// check if two name ids can be seen as identical (in presence of refs/others)
|
||||||
|
// in our case this translates into no name announcement in either direction (lhs->rhs and
|
||||||
|
// rhs->lhs)
|
||||||
|
bool HaveIdenticalNames(const NameID lhs,
|
||||||
|
const NameID rhs,
|
||||||
|
const util::NameTable &name_table,
|
||||||
|
const SuffixTable &street_name_suffix_table)
|
||||||
|
{
|
||||||
|
const auto non_empty = (lhs != EMPTY_NAMEID) && (rhs != EMPTY_NAMEID);
|
||||||
|
|
||||||
|
// symmetrical check for announcements
|
||||||
|
return non_empty &&
|
||||||
|
!util::guidance::requiresNameAnnounced(lhs, rhs, name_table, street_name_suffix_table) &&
|
||||||
|
!util::guidance::requiresNameAnnounced(rhs, lhs, name_table, street_name_suffix_table);
|
||||||
|
}
|
||||||
|
|
||||||
|
} // namespace guidance
|
||||||
|
} // namespace extractor
|
||||||
|
} // namespace osrm
|
||||||
|
|
||||||
|
#endif /*OSRM_EXTRACTOR_GUIDANCE_HAVE_IDENTICAL_NAMES_HPP_*/
|
||||||
@@ -102,6 +102,19 @@ TurnType::Enum IntersectionHandler::findBasicTurnType(const EdgeID via_edge,
|
|||||||
return TurnType::Turn;
|
return TurnType::Turn;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
TurnType::Enum IntersectionHandler::areSameClasses(const EdgeID via_edge,
|
||||||
|
const ConnectedRoad &road) const
|
||||||
|
{
|
||||||
|
const auto &in_classes =
|
||||||
|
node_data_container.GetAnnotation(node_based_graph.GetEdgeData(via_edge).annotation_data)
|
||||||
|
.classes;
|
||||||
|
const auto &out_classes =
|
||||||
|
node_data_container.GetAnnotation(node_based_graph.GetEdgeData(road.eid).annotation_data)
|
||||||
|
.classes;
|
||||||
|
|
||||||
|
return in_classes == out_classes;
|
||||||
|
}
|
||||||
|
|
||||||
TurnInstruction IntersectionHandler::getInstructionForObvious(const std::size_t num_roads,
|
TurnInstruction IntersectionHandler::getInstructionForObvious(const std::size_t num_roads,
|
||||||
const EdgeID via_edge,
|
const EdgeID via_edge,
|
||||||
const bool through_street,
|
const bool through_street,
|
||||||
@@ -195,7 +208,8 @@ TurnInstruction IntersectionHandler::getInstructionForObvious(const std::size_t
|
|||||||
if (needs_notification)
|
if (needs_notification)
|
||||||
return {TurnType::Notification, getTurnDirection(road.angle)};
|
return {TurnType::Notification, getTurnDirection(road.angle)};
|
||||||
else
|
else
|
||||||
return {num_roads == 2 ? TurnType::NoTurn : TurnType::Suppressed,
|
return {num_roads == 2 && areSameClasses(via_edge, road) ? TurnType::NoTurn
|
||||||
|
: TurnType::Suppressed,
|
||||||
getTurnDirection(road.angle)};
|
getTurnDirection(road.angle)};
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -204,7 +218,7 @@ TurnInstruction IntersectionHandler::getInstructionForObvious(const std::size_t
|
|||||||
{
|
{
|
||||||
return {TurnType::Notification, getTurnDirection(road.angle)};
|
return {TurnType::Notification, getTurnDirection(road.angle)};
|
||||||
}
|
}
|
||||||
if (num_roads > 2)
|
if (num_roads > 2 || !areSameClasses(via_edge, road))
|
||||||
{
|
{
|
||||||
return {TurnType::Suppressed, getTurnDirection(road.angle)};
|
return {TurnType::Suppressed, getTurnDirection(road.angle)};
|
||||||
}
|
}
|
||||||
@@ -418,44 +432,6 @@ void IntersectionHandler::assignTrivialTurns(const EdgeID via_eid,
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
bool IntersectionHandler::isThroughStreet(const std::size_t index,
|
|
||||||
const Intersection &intersection) const
|
|
||||||
{
|
|
||||||
const auto &data_at_index = node_data_container.GetAnnotation(
|
|
||||||
node_based_graph.GetEdgeData(intersection[index].eid).annotation_data);
|
|
||||||
|
|
||||||
if (data_at_index.name_id == EMPTY_NAMEID)
|
|
||||||
return false;
|
|
||||||
|
|
||||||
// a through street cannot start at our own position -> index 1
|
|
||||||
for (std::size_t road_index = 1; road_index < intersection.size(); ++road_index)
|
|
||||||
{
|
|
||||||
if (road_index == index)
|
|
||||||
continue;
|
|
||||||
|
|
||||||
const auto &road = intersection[road_index];
|
|
||||||
const auto &road_data = node_data_container.GetAnnotation(
|
|
||||||
node_based_graph.GetEdgeData(road.eid).annotation_data);
|
|
||||||
|
|
||||||
// roads have a near straight angle (180 degree)
|
|
||||||
const bool is_nearly_straight = angularDeviation(road.angle, intersection[index].angle) >
|
|
||||||
(STRAIGHT_ANGLE - FUZZY_ANGLE_DIFFERENCE);
|
|
||||||
|
|
||||||
const bool have_same_name =
|
|
||||||
road_data.name_id != EMPTY_NAMEID &&
|
|
||||||
!util::guidance::requiresNameAnnounced(
|
|
||||||
data_at_index.name_id, road_data.name_id, name_table, street_name_suffix_table);
|
|
||||||
|
|
||||||
const bool have_same_category =
|
|
||||||
node_based_graph.GetEdgeData(intersection[index].eid).flags.road_classification ==
|
|
||||||
node_based_graph.GetEdgeData(road.eid).flags.road_classification;
|
|
||||||
|
|
||||||
if (is_nearly_straight && have_same_name && have_same_category)
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
boost::optional<IntersectionHandler::IntersectionViewAndNode>
|
boost::optional<IntersectionHandler::IntersectionViewAndNode>
|
||||||
IntersectionHandler::getNextIntersection(const NodeID at, const EdgeID via) const
|
IntersectionHandler::getNextIntersection(const NodeID at, const EdgeID via) const
|
||||||
{
|
{
|
||||||
|
|||||||
@@ -122,16 +122,6 @@ bool MergableRoadDetector::CanMergeRoad(const NodeID intersection_node,
|
|||||||
!IsCircularShape(intersection_node, lhs, rhs);
|
!IsCircularShape(intersection_node, lhs, rhs);
|
||||||
}
|
}
|
||||||
|
|
||||||
bool MergableRoadDetector::HaveIdenticalNames(const NameID lhs, const NameID rhs) const
|
|
||||||
{
|
|
||||||
const auto non_empty = (lhs != EMPTY_NAMEID) && (rhs != EMPTY_NAMEID);
|
|
||||||
|
|
||||||
// symmetrical check for announcements
|
|
||||||
return non_empty &&
|
|
||||||
!util::guidance::requiresNameAnnounced(lhs, rhs, name_table, street_name_suffix_table) &&
|
|
||||||
!util::guidance::requiresNameAnnounced(rhs, lhs, name_table, street_name_suffix_table);
|
|
||||||
}
|
|
||||||
|
|
||||||
bool MergableRoadDetector::IsDistinctFrom(const MergableRoadData &lhs,
|
bool MergableRoadDetector::IsDistinctFrom(const MergableRoadData &lhs,
|
||||||
const MergableRoadData &rhs) const
|
const MergableRoadData &rhs) const
|
||||||
{
|
{
|
||||||
@@ -143,7 +133,9 @@ bool MergableRoadDetector::IsDistinctFrom(const MergableRoadData &lhs,
|
|||||||
node_data_container.GetAnnotation(node_based_graph.GetEdgeData(lhs.eid).annotation_data)
|
node_data_container.GetAnnotation(node_based_graph.GetEdgeData(lhs.eid).annotation_data)
|
||||||
.name_id,
|
.name_id,
|
||||||
node_data_container.GetAnnotation(node_based_graph.GetEdgeData(rhs.eid).annotation_data)
|
node_data_container.GetAnnotation(node_based_graph.GetEdgeData(rhs.eid).annotation_data)
|
||||||
.name_id);
|
.name_id,
|
||||||
|
name_table,
|
||||||
|
street_name_suffix_table);
|
||||||
}
|
}
|
||||||
|
|
||||||
bool MergableRoadDetector::EdgeDataSupportsMerge(
|
bool MergableRoadDetector::EdgeDataSupportsMerge(
|
||||||
@@ -165,7 +157,8 @@ bool MergableRoadDetector::EdgeDataSupportsMerge(
|
|||||||
return false;
|
return false;
|
||||||
|
|
||||||
// we require valid names
|
// we require valid names
|
||||||
if (!HaveIdenticalNames(lhs_annotation.name_id, rhs_annotation.name_id))
|
if (!HaveIdenticalNames(
|
||||||
|
lhs_annotation.name_id, rhs_annotation.name_id, name_table, street_name_suffix_table))
|
||||||
return false;
|
return false;
|
||||||
|
|
||||||
return lhs_flags.road_classification == rhs_flags.road_classification;
|
return lhs_flags.road_classification == rhs_flags.road_classification;
|
||||||
|
|||||||
@@ -239,7 +239,12 @@ Intersection MotorwayHandler::fromMotorway(const EdgeID via_eid, Intersection in
|
|||||||
intersection[1].instruction =
|
intersection[1].instruction =
|
||||||
getInstructionForObvious(intersection.size(),
|
getInstructionForObvious(intersection.size(),
|
||||||
via_eid,
|
via_eid,
|
||||||
isThroughStreet(1, intersection),
|
isThroughStreet(1,
|
||||||
|
intersection,
|
||||||
|
node_based_graph,
|
||||||
|
node_data_container,
|
||||||
|
name_table,
|
||||||
|
street_name_suffix_table),
|
||||||
intersection[1]);
|
intersection[1]);
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
@@ -253,8 +258,16 @@ Intersection MotorwayHandler::fromMotorway(const EdgeID via_eid, Intersection in
|
|||||||
|
|
||||||
if (road.angle == continue_angle)
|
if (road.angle == continue_angle)
|
||||||
{
|
{
|
||||||
road.instruction = getInstructionForObvious(
|
road.instruction =
|
||||||
intersection.size(), via_eid, isThroughStreet(1, intersection), road);
|
getInstructionForObvious(intersection.size(),
|
||||||
|
via_eid,
|
||||||
|
isThroughStreet(1,
|
||||||
|
intersection,
|
||||||
|
node_based_graph,
|
||||||
|
node_data_container,
|
||||||
|
name_table,
|
||||||
|
street_name_suffix_table),
|
||||||
|
road);
|
||||||
}
|
}
|
||||||
else if (road.angle < continue_angle)
|
else if (road.angle < continue_angle)
|
||||||
{
|
{
|
||||||
@@ -353,8 +366,16 @@ Intersection MotorwayHandler::fromRamp(const EdgeID via_eid, Intersection inters
|
|||||||
BOOST_ASSERT(!intersection[0].entry_allowed);
|
BOOST_ASSERT(!intersection[0].entry_allowed);
|
||||||
BOOST_ASSERT(isMotorwayClass(intersection[1].eid, node_based_graph));
|
BOOST_ASSERT(isMotorwayClass(intersection[1].eid, node_based_graph));
|
||||||
|
|
||||||
intersection[1].instruction = getInstructionForObvious(
|
intersection[1].instruction =
|
||||||
intersection.size(), via_eid, isThroughStreet(1, intersection), intersection[1]);
|
getInstructionForObvious(intersection.size(),
|
||||||
|
via_eid,
|
||||||
|
isThroughStreet(1,
|
||||||
|
intersection,
|
||||||
|
node_based_graph,
|
||||||
|
node_data_container,
|
||||||
|
name_table,
|
||||||
|
street_name_suffix_table),
|
||||||
|
intersection[1]);
|
||||||
}
|
}
|
||||||
else if (intersection.size() == 3)
|
else if (intersection.size() == 3)
|
||||||
{
|
{
|
||||||
@@ -404,7 +425,12 @@ Intersection MotorwayHandler::fromRamp(const EdgeID via_eid, Intersection inters
|
|||||||
intersection[1].instruction =
|
intersection[1].instruction =
|
||||||
getInstructionForObvious(intersection.size(),
|
getInstructionForObvious(intersection.size(),
|
||||||
via_eid,
|
via_eid,
|
||||||
isThroughStreet(1, intersection),
|
isThroughStreet(1,
|
||||||
|
intersection,
|
||||||
|
node_based_graph,
|
||||||
|
node_data_container,
|
||||||
|
name_table,
|
||||||
|
street_name_suffix_table),
|
||||||
intersection[1]);
|
intersection[1]);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -429,7 +455,12 @@ Intersection MotorwayHandler::fromRamp(const EdgeID via_eid, Intersection inters
|
|||||||
intersection[2].instruction =
|
intersection[2].instruction =
|
||||||
getInstructionForObvious(intersection.size(),
|
getInstructionForObvious(intersection.size(),
|
||||||
via_eid,
|
via_eid,
|
||||||
isThroughStreet(2, intersection),
|
isThroughStreet(2,
|
||||||
|
intersection,
|
||||||
|
node_based_graph,
|
||||||
|
node_data_container,
|
||||||
|
name_table,
|
||||||
|
street_name_suffix_table),
|
||||||
intersection[2]);
|
intersection[2]);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -478,8 +478,16 @@ Intersection RoundaboutHandler::handleRoundabouts(const RoundaboutType roundabou
|
|||||||
if (util::angularDeviation(turn.angle, STRAIGHT_ANGLE) < FUZZY_ANGLE_DIFFERENCE &&
|
if (util::angularDeviation(turn.angle, STRAIGHT_ANGLE) < FUZZY_ANGLE_DIFFERENCE &&
|
||||||
crossing_roundabout)
|
crossing_roundabout)
|
||||||
{
|
{
|
||||||
turn.instruction = getInstructionForObvious(
|
turn.instruction =
|
||||||
intersection.size(), via_eid, isThroughStreet(idx, intersection), turn);
|
getInstructionForObvious(intersection.size(),
|
||||||
|
via_eid,
|
||||||
|
isThroughStreet(idx,
|
||||||
|
intersection,
|
||||||
|
node_based_graph,
|
||||||
|
node_data_container,
|
||||||
|
name_table,
|
||||||
|
street_name_suffix_table),
|
||||||
|
turn);
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
|
|||||||
@@ -344,9 +344,24 @@ operator()(const NodeID /*nid*/, const EdgeID source_edge_id, Intersection inter
|
|||||||
}
|
}
|
||||||
|
|
||||||
// If the sliproad candidate is a through street, we cannot handle it as a sliproad.
|
// If the sliproad candidate is a through street, we cannot handle it as a sliproad.
|
||||||
if (isThroughStreet(sliproad_edge, target_intersection))
|
auto sliproad_in_target_intersection =
|
||||||
|
std::find_if(begin(target_intersection),
|
||||||
|
end(target_intersection),
|
||||||
|
[&](const auto &road) { return road.eid == sliproad_edge; });
|
||||||
|
if (sliproad_in_target_intersection != target_intersection.end())
|
||||||
{
|
{
|
||||||
continue;
|
auto index_of_sliproad_in_target_intersection =
|
||||||
|
sliproad_in_target_intersection - target_intersection.begin();
|
||||||
|
|
||||||
|
if (isThroughStreet<IntersectionView>(index_of_sliproad_in_target_intersection,
|
||||||
|
target_intersection,
|
||||||
|
node_based_graph,
|
||||||
|
node_data_container,
|
||||||
|
name_table,
|
||||||
|
street_name_suffix_table))
|
||||||
|
{
|
||||||
|
continue;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// The turn off of the Sliproad has to be obvious and a narrow turn and must not be a
|
// The turn off of the Sliproad has to be obvious and a narrow turn and must not be a
|
||||||
@@ -689,32 +704,6 @@ bool SliproadHandler::nextIntersectionIsTooFarAway(const NodeID start, const Edg
|
|||||||
return accumulator.too_far_away;
|
return accumulator.too_far_away;
|
||||||
}
|
}
|
||||||
|
|
||||||
bool SliproadHandler::isThroughStreet(const EdgeID from, const IntersectionView &intersection) const
|
|
||||||
{
|
|
||||||
BOOST_ASSERT(from != SPECIAL_EDGEID);
|
|
||||||
BOOST_ASSERT(!intersection.empty());
|
|
||||||
|
|
||||||
const auto from_annotation_id = node_based_graph.GetEdgeData(from).annotation_data;
|
|
||||||
const auto &edge_name_id = node_data_container.GetAnnotation(from_annotation_id).name_id;
|
|
||||||
|
|
||||||
auto first = begin(intersection) + 1; // Skip UTurn road
|
|
||||||
auto last = end(intersection);
|
|
||||||
|
|
||||||
auto same_name = [&](const auto &road) {
|
|
||||||
const auto annotation_id = node_based_graph.GetEdgeData(road.eid).annotation_data;
|
|
||||||
const auto &road_name_id = node_data_container.GetAnnotation(annotation_id).name_id;
|
|
||||||
|
|
||||||
return edge_name_id != EMPTY_NAMEID && //
|
|
||||||
road_name_id != EMPTY_NAMEID && //
|
|
||||||
!util::guidance::requiresNameAnnounced(edge_name_id,
|
|
||||||
road_name_id,
|
|
||||||
name_table,
|
|
||||||
street_name_suffix_table); //
|
|
||||||
};
|
|
||||||
|
|
||||||
return std::find_if(first, last, same_name) != last;
|
|
||||||
}
|
|
||||||
|
|
||||||
bool SliproadHandler::roadContinues(const EdgeID current, const EdgeID next) const
|
bool SliproadHandler::roadContinues(const EdgeID current, const EdgeID next) const
|
||||||
{
|
{
|
||||||
const auto ¤t_data =
|
const auto ¤t_data =
|
||||||
|
|||||||
@@ -287,8 +287,16 @@ Intersection TurnHandler::handleThreeWayTurn(const EdgeID via_edge, Intersection
|
|||||||
const auto direction_at_two = getTurnDirection(intersection[2].angle);
|
const auto direction_at_two = getTurnDirection(intersection[2].angle);
|
||||||
if (obvious_index == 1)
|
if (obvious_index == 1)
|
||||||
{
|
{
|
||||||
intersection[1].instruction = getInstructionForObvious(
|
intersection[1].instruction =
|
||||||
3, via_edge, isThroughStreet(1, intersection), intersection[1]);
|
getInstructionForObvious(3,
|
||||||
|
via_edge,
|
||||||
|
isThroughStreet(1,
|
||||||
|
intersection,
|
||||||
|
node_based_graph,
|
||||||
|
node_data_container,
|
||||||
|
name_table,
|
||||||
|
street_name_suffix_table),
|
||||||
|
intersection[1]);
|
||||||
const auto second_direction = (direction_at_one == direction_at_two &&
|
const auto second_direction = (direction_at_one == direction_at_two &&
|
||||||
direction_at_two == DirectionModifier::Straight)
|
direction_at_two == DirectionModifier::Straight)
|
||||||
? DirectionModifier::SlightLeft
|
? DirectionModifier::SlightLeft
|
||||||
@@ -300,8 +308,16 @@ Intersection TurnHandler::handleThreeWayTurn(const EdgeID via_edge, Intersection
|
|||||||
else
|
else
|
||||||
{
|
{
|
||||||
BOOST_ASSERT(obvious_index == 2);
|
BOOST_ASSERT(obvious_index == 2);
|
||||||
intersection[2].instruction = getInstructionForObvious(
|
intersection[2].instruction =
|
||||||
3, via_edge, isThroughStreet(2, intersection), intersection[2]);
|
getInstructionForObvious(3,
|
||||||
|
via_edge,
|
||||||
|
isThroughStreet(2,
|
||||||
|
intersection,
|
||||||
|
node_based_graph,
|
||||||
|
node_data_container,
|
||||||
|
name_table,
|
||||||
|
street_name_suffix_table),
|
||||||
|
intersection[2]);
|
||||||
const auto first_direction = (direction_at_one == direction_at_two &&
|
const auto first_direction = (direction_at_one == direction_at_two &&
|
||||||
direction_at_one == DirectionModifier::Straight)
|
direction_at_one == DirectionModifier::Straight)
|
||||||
? DirectionModifier::SlightRight
|
? DirectionModifier::SlightRight
|
||||||
@@ -336,7 +352,12 @@ Intersection TurnHandler::handleComplexTurn(const EdgeID via_edge, Intersection
|
|||||||
intersection[obvious_index].instruction =
|
intersection[obvious_index].instruction =
|
||||||
getInstructionForObvious(intersection.size(),
|
getInstructionForObvious(intersection.size(),
|
||||||
via_edge,
|
via_edge,
|
||||||
isThroughStreet(obvious_index, intersection),
|
isThroughStreet(obvious_index,
|
||||||
|
intersection,
|
||||||
|
node_based_graph,
|
||||||
|
node_data_container,
|
||||||
|
name_table,
|
||||||
|
street_name_suffix_table),
|
||||||
intersection[obvious_index]);
|
intersection[obvious_index]);
|
||||||
|
|
||||||
// assign left/right turns
|
// assign left/right turns
|
||||||
|
|||||||
@@ -294,8 +294,12 @@ getIntersectionGeometries(const util::NodeBasedDynamicGraph &graph,
|
|||||||
|
|
||||||
lhs.perceived_bearing = lhs.initial_bearing = merge.second;
|
lhs.perceived_bearing = lhs.initial_bearing = merge.second;
|
||||||
rhs.perceived_bearing = rhs.initial_bearing = merge.second;
|
rhs.perceived_bearing = rhs.initial_bearing = merge.second;
|
||||||
merged_edge_ids.insert(lhs.edge);
|
|
||||||
merged_edge_ids.insert(rhs.edge);
|
// Only one of the edges must be reversed, mark it as merged to remove from
|
||||||
|
// intersection view
|
||||||
|
BOOST_ASSERT(graph.GetEdgeData(lhs.edge).reversed ^
|
||||||
|
graph.GetEdgeData(rhs.edge).reversed);
|
||||||
|
merged_edge_ids.insert(graph.GetEdgeData(lhs.edge).reversed ? lhs.edge : rhs.edge);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -107,12 +107,12 @@ RestrictionParser::TryParse(const osmium::Relation &relation) const
|
|||||||
const std::string value(fi_begin->value());
|
const std::string value(fi_begin->value());
|
||||||
|
|
||||||
// documented OSM restriction tags start either with only_* or no_*;
|
// documented OSM restriction tags start either with only_* or no_*;
|
||||||
// check and return on these values, and ignore unrecognized values
|
// check and return on these values, and ignore no_*_on_red or unrecognized values
|
||||||
if (value.find("only_") == 0)
|
if (value.find("only_") == 0)
|
||||||
{
|
{
|
||||||
is_only_restriction = true;
|
is_only_restriction = true;
|
||||||
}
|
}
|
||||||
else if (value.find("no_") == 0)
|
else if (value.find("no_") == 0 && !boost::algorithm::ends_with(value, "_on_red"))
|
||||||
{
|
{
|
||||||
is_only_restriction = false;
|
is_only_restriction = false;
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -19,8 +19,6 @@
|
|||||||
|
|
||||||
#include <osmium/osm.hpp>
|
#include <osmium/osm.hpp>
|
||||||
|
|
||||||
#include <tbb/parallel_for.h>
|
|
||||||
|
|
||||||
#include <memory>
|
#include <memory>
|
||||||
#include <sstream>
|
#include <sstream>
|
||||||
|
|
||||||
|
|||||||
@@ -2,8 +2,6 @@
|
|||||||
|
|
||||||
#include "util/permutation.hpp"
|
#include "util/permutation.hpp"
|
||||||
|
|
||||||
#include <tbb/parallel_sort.h>
|
|
||||||
|
|
||||||
namespace osrm
|
namespace osrm
|
||||||
{
|
{
|
||||||
namespace partition
|
namespace partition
|
||||||
|
|||||||
@@ -27,7 +27,8 @@ struct URLParser final : qi::grammar<Iterator, Into>
|
|||||||
using boost::spirit::repository::qi::iter_pos;
|
using boost::spirit::repository::qi::iter_pos;
|
||||||
|
|
||||||
alpha_numeral = qi::char_("a-zA-Z0-9");
|
alpha_numeral = qi::char_("a-zA-Z0-9");
|
||||||
percent_encoding = qi::char_('%') > qi::uint_parser<char, 16, 2, 2>()[qi::_val = qi::_1];
|
percent_encoding =
|
||||||
|
qi::char_('%') > qi::uint_parser<unsigned char, 16, 2, 2>()[qi::_val = qi::_1];
|
||||||
polyline_chars = qi::char_("a-zA-Z0-9_.--[]{}@?|\\~`^") | percent_encoding;
|
polyline_chars = qi::char_("a-zA-Z0-9_.--[]{}@?|\\~`^") | percent_encoding;
|
||||||
all_chars = polyline_chars | qi::char_("=,;:&().");
|
all_chars = polyline_chars | qi::char_("=,;:&().");
|
||||||
|
|
||||||
|
|||||||
@@ -33,10 +33,11 @@
|
|||||||
#include <boost/interprocess/mapped_region.hpp>
|
#include <boost/interprocess/mapped_region.hpp>
|
||||||
|
|
||||||
#include <tbb/blocked_range.h>
|
#include <tbb/blocked_range.h>
|
||||||
#include <tbb/concurrent_unordered_map.h>
|
#include <tbb/concurrent_vector.h>
|
||||||
#include <tbb/enumerable_thread_specific.h>
|
#include <tbb/enumerable_thread_specific.h>
|
||||||
#include <tbb/parallel_for_each.h>
|
#include <tbb/parallel_for.h>
|
||||||
#include <tbb/parallel_invoke.h>
|
#include <tbb/parallel_invoke.h>
|
||||||
|
#include <tbb/parallel_sort.h>
|
||||||
|
|
||||||
#include <algorithm>
|
#include <algorithm>
|
||||||
#include <atomic>
|
#include <atomic>
|
||||||
|
|||||||
@@ -10,7 +10,7 @@ exports.three_test_coordinates = [[7.41337, 43.72956],
|
|||||||
|
|
||||||
exports.two_test_coordinates = exports.three_test_coordinates.slice(0, 2)
|
exports.two_test_coordinates = exports.three_test_coordinates.slice(0, 2)
|
||||||
|
|
||||||
exports.test_tile = {'at': [17059, 11948, 15], 'size': 168606};
|
exports.test_tile = {'at': [17059, 11948, 15], 'size': 169239};
|
||||||
|
|
||||||
|
|
||||||
// Test files generated by the routing engine; check test/data
|
// Test files generated by the routing engine; check test/data
|
||||||
|
|||||||
@@ -238,3 +238,89 @@ test('match: match in Monaco without motorways', function(assert) {
|
|||||||
assert.equal(response.matchings.length, 1);
|
assert.equal(response.matchings.length, 1);
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
|
||||||
|
test('match: throws on invalid waypoints values needs at least two', function(assert) {
|
||||||
|
assert.plan(1);
|
||||||
|
var osrm = new OSRM(data_path);
|
||||||
|
var options = {
|
||||||
|
steps: true,
|
||||||
|
coordinates: three_test_coordinates,
|
||||||
|
waypoints: [0]
|
||||||
|
};
|
||||||
|
assert.throws(function() { osrm.match(options, function(err, response) {}); },
|
||||||
|
'At least two waypoints must be provided');
|
||||||
|
});
|
||||||
|
|
||||||
|
test('match: throws on invalid waypoints values, needs first and last coordinate indices', function(assert) {
|
||||||
|
assert.plan(1);
|
||||||
|
var osrm = new OSRM(data_path);
|
||||||
|
var options = {
|
||||||
|
steps: true,
|
||||||
|
coordinates: three_test_coordinates,
|
||||||
|
waypoints: [1, 2]
|
||||||
|
};
|
||||||
|
assert.throws(function() { osrm.match(options, function(err, response) {console.log(err);}); },
|
||||||
|
'First and last waypoints values must correspond to first and last coordinate indices');
|
||||||
|
});
|
||||||
|
|
||||||
|
test('match: throws on invalid waypoints values, order matters', function(assert) {
|
||||||
|
assert.plan(1);
|
||||||
|
var osrm = new OSRM(data_path);
|
||||||
|
var options = {
|
||||||
|
steps: true,
|
||||||
|
coordinates: three_test_coordinates,
|
||||||
|
waypoints: [2, 0]
|
||||||
|
};
|
||||||
|
assert.throws(function() { osrm.match(options, function(err, response) {console.log(err);}); },
|
||||||
|
'First and last waypoints values must correspond to first and last coordinate indices');
|
||||||
|
});
|
||||||
|
|
||||||
|
test('match: throws on invalid waypoints values, waypoints must correspond with a coordinate index', function(assert) {
|
||||||
|
assert.plan(1);
|
||||||
|
var osrm = new OSRM(data_path);
|
||||||
|
var options = {
|
||||||
|
steps: true,
|
||||||
|
coordinates: three_test_coordinates,
|
||||||
|
waypoints: [0, 3, 2]
|
||||||
|
};
|
||||||
|
assert.throws(function() { osrm.match(options, function(err, response) {console.log(err);}); },
|
||||||
|
'Waypoints must correspond with the index of an input coordinate');
|
||||||
|
});
|
||||||
|
|
||||||
|
test('match: error on split trace', function(assert) {
|
||||||
|
assert.plan(1);
|
||||||
|
var osrm = new OSRM(data_path);
|
||||||
|
var four_coords = Array.from(three_test_coordinates);
|
||||||
|
four_coords.push([7.41902,43.73487]);
|
||||||
|
var options = {
|
||||||
|
steps: true,
|
||||||
|
coordinates: four_coords,
|
||||||
|
timestamps: [1700, 1750, 1424684616, 1424684620],
|
||||||
|
waypoints: [0,3]
|
||||||
|
};
|
||||||
|
osrm.match(options, function(err, response) {
|
||||||
|
assert.ok(err, 'Errors with NoMatch');
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
||||||
|
test('match: match in Monaco with waypoints', function(assert) {
|
||||||
|
assert.plan(6);
|
||||||
|
var osrm = new OSRM(data_path);
|
||||||
|
var options = {
|
||||||
|
steps: true,
|
||||||
|
coordinates: three_test_coordinates,
|
||||||
|
waypoints: [0,2]
|
||||||
|
};
|
||||||
|
osrm.match(options, function(err, response) {
|
||||||
|
assert.ifError(err);
|
||||||
|
assert.equal(response.matchings.length, 1);
|
||||||
|
assert.equal(response.matchings[0].legs.length, 1);
|
||||||
|
assert.ok(response.matchings.every(function(m) {
|
||||||
|
return !!m.distance && !!m.duration && Array.isArray(m.legs) && !!m.geometry && m.confidence > 0;
|
||||||
|
}))
|
||||||
|
assert.equal(response.tracepoints.length, 3);
|
||||||
|
assert.ok(response.tracepoints.every(function(t) {
|
||||||
|
return !!t.hint && !isNaN(t.matchings_index) && !isNaN(t.waypoint_index) && !!t.name;
|
||||||
|
}));
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|||||||
@@ -0,0 +1,148 @@
|
|||||||
|
#include "engine/internal_route_result.hpp"
|
||||||
|
#include "engine/phantom_node.hpp"
|
||||||
|
|
||||||
|
#include <boost/test/test_case_template.hpp>
|
||||||
|
#include <boost/test/unit_test.hpp>
|
||||||
|
|
||||||
|
#include <algorithm>
|
||||||
|
#include <iterator>
|
||||||
|
#include <vector>
|
||||||
|
|
||||||
|
BOOST_AUTO_TEST_SUITE(collapse_test)
|
||||||
|
|
||||||
|
using namespace osrm;
|
||||||
|
using namespace osrm::util;
|
||||||
|
using namespace osrm::engine;
|
||||||
|
|
||||||
|
BOOST_AUTO_TEST_CASE(unchanged_collapse_route_result)
|
||||||
|
{
|
||||||
|
PhantomNode source;
|
||||||
|
PhantomNode target;
|
||||||
|
source.forward_segment_id = {1, true};
|
||||||
|
target.forward_segment_id = {6, true};
|
||||||
|
PathData pathy{2, 17, false, 2, 3, 4, 5, 0, {}, 4, 2, {}, 2, {1.0}, {1.0}, false};
|
||||||
|
PathData kathy{1, 16, false, 1, 2, 3, 4, 1, {}, 3, 1, {}, 1, {2.0}, {3.0}, false};
|
||||||
|
InternalRouteResult one_leg_result;
|
||||||
|
one_leg_result.unpacked_path_segments = {{pathy, kathy}};
|
||||||
|
one_leg_result.segment_end_coordinates = {PhantomNodes{source, target}};
|
||||||
|
one_leg_result.source_traversed_in_reverse = {true};
|
||||||
|
one_leg_result.target_traversed_in_reverse = {true};
|
||||||
|
one_leg_result.shortest_path_weight = 50;
|
||||||
|
|
||||||
|
auto collapsed = CollapseInternalRouteResult(one_leg_result, {true, true});
|
||||||
|
BOOST_CHECK_EQUAL(one_leg_result.unpacked_path_segments[0].front().turn_via_node,
|
||||||
|
collapsed.unpacked_path_segments[0].front().turn_via_node);
|
||||||
|
BOOST_CHECK_EQUAL(one_leg_result.unpacked_path_segments[0].back().turn_via_node,
|
||||||
|
collapsed.unpacked_path_segments[0].back().turn_via_node);
|
||||||
|
}
|
||||||
|
|
||||||
|
BOOST_AUTO_TEST_CASE(two_legs_to_one_leg)
|
||||||
|
{
|
||||||
|
PathData pathy{2, 17, false, 2, 3, 4, 5, 0, {}, 4, 2, {}, 2, {1.0}, {1.0}, false};
|
||||||
|
PathData kathy{1, 16, false, 1, 2, 3, 4, 1, {}, 3, 1, {}, 1, {2.0}, {3.0}, false};
|
||||||
|
PathData cathy{3, 16, false, 1, 2, 3, 4, 1, {}, 3, 1, {}, 1, {2.0}, {3.0}, false};
|
||||||
|
PhantomNode node_1;
|
||||||
|
PhantomNode node_2;
|
||||||
|
PhantomNode node_3;
|
||||||
|
node_1.forward_segment_id = {1, true};
|
||||||
|
node_2.forward_segment_id = {6, true};
|
||||||
|
node_3.forward_segment_id = {12, true};
|
||||||
|
InternalRouteResult two_leg_result;
|
||||||
|
two_leg_result.unpacked_path_segments = {{pathy, kathy}, {kathy, cathy}};
|
||||||
|
two_leg_result.segment_end_coordinates = {PhantomNodes{node_1, node_2},
|
||||||
|
PhantomNodes{node_2, node_3}};
|
||||||
|
two_leg_result.source_traversed_in_reverse = {true, false};
|
||||||
|
two_leg_result.target_traversed_in_reverse = {true, false};
|
||||||
|
two_leg_result.shortest_path_weight = 80;
|
||||||
|
|
||||||
|
auto collapsed = CollapseInternalRouteResult(two_leg_result, {true, false, true, true});
|
||||||
|
BOOST_CHECK_EQUAL(collapsed.unpacked_path_segments.size(), 1);
|
||||||
|
BOOST_CHECK_EQUAL(collapsed.segment_end_coordinates.size(), 1);
|
||||||
|
BOOST_CHECK_EQUAL(collapsed.segment_end_coordinates[0].target_phantom.forward_segment_id.id,
|
||||||
|
12);
|
||||||
|
BOOST_CHECK_EQUAL(collapsed.segment_end_coordinates[0].source_phantom.forward_segment_id.id, 1);
|
||||||
|
BOOST_CHECK_EQUAL(collapsed.unpacked_path_segments[0].size(), 3);
|
||||||
|
BOOST_CHECK_EQUAL(collapsed.unpacked_path_segments[0][0].turn_via_node, 2);
|
||||||
|
BOOST_CHECK_EQUAL(collapsed.unpacked_path_segments[0][1].turn_via_node, 1);
|
||||||
|
BOOST_CHECK_EQUAL(collapsed.unpacked_path_segments[0][2].turn_via_node, 3);
|
||||||
|
}
|
||||||
|
|
||||||
|
BOOST_AUTO_TEST_CASE(three_legs_to_two_legs)
|
||||||
|
{
|
||||||
|
PathData pathy{2, 17, false, 2, 3, 4, 5, 0, {}, 4, 2, {}, 2, {1.0}, {1.0}, false};
|
||||||
|
PathData kathy{1, 16, false, 1, 2, 3, 4, 1, {}, 3, 1, {}, 1, {2.0}, {3.0}, false};
|
||||||
|
PathData qathy{5, 16, false, 1, 2, 3, 4, 1, {}, 3, 1, {}, 1, {2.0}, {3.0}, false};
|
||||||
|
PathData cathy{3, 16, false, 1, 2, 3, 4, 1, {}, 3, 1, {}, 1, {2.0}, {3.0}, false};
|
||||||
|
PathData mathy{4, 18, false, 8, 9, 13, 4, 2, {}, 4, 2, {}, 2, {3.0}, {1.0}, false};
|
||||||
|
PhantomNode node_1;
|
||||||
|
PhantomNode node_2;
|
||||||
|
PhantomNode node_3;
|
||||||
|
PhantomNode node_4;
|
||||||
|
node_1.forward_segment_id = {1, true};
|
||||||
|
node_2.forward_segment_id = {6, true};
|
||||||
|
node_3.forward_segment_id = {12, true};
|
||||||
|
node_4.forward_segment_id = {18, true};
|
||||||
|
InternalRouteResult three_leg_result;
|
||||||
|
three_leg_result.unpacked_path_segments = {std::vector<PathData>{pathy, kathy},
|
||||||
|
std::vector<PathData>{kathy, qathy, cathy},
|
||||||
|
std::vector<PathData>{cathy, mathy}};
|
||||||
|
three_leg_result.segment_end_coordinates = {
|
||||||
|
PhantomNodes{node_1, node_2}, PhantomNodes{node_2, node_3}, PhantomNodes{node_3, node_4}};
|
||||||
|
three_leg_result.source_traversed_in_reverse = {true, false, true},
|
||||||
|
three_leg_result.target_traversed_in_reverse = {true, false, true},
|
||||||
|
three_leg_result.shortest_path_weight = 140;
|
||||||
|
|
||||||
|
auto collapsed = CollapseInternalRouteResult(three_leg_result, {true, true, false, true});
|
||||||
|
BOOST_CHECK_EQUAL(collapsed.unpacked_path_segments.size(), 2);
|
||||||
|
BOOST_CHECK_EQUAL(collapsed.segment_end_coordinates.size(), 2);
|
||||||
|
BOOST_CHECK_EQUAL(collapsed.segment_end_coordinates[0].source_phantom.forward_segment_id.id, 1);
|
||||||
|
BOOST_CHECK_EQUAL(collapsed.segment_end_coordinates[0].target_phantom.forward_segment_id.id, 6);
|
||||||
|
BOOST_CHECK_EQUAL(collapsed.segment_end_coordinates[1].source_phantom.forward_segment_id.id, 6);
|
||||||
|
BOOST_CHECK_EQUAL(collapsed.segment_end_coordinates[1].target_phantom.forward_segment_id.id,
|
||||||
|
18);
|
||||||
|
BOOST_CHECK_EQUAL(collapsed.unpacked_path_segments[0].size(), 2);
|
||||||
|
BOOST_CHECK_EQUAL(collapsed.unpacked_path_segments[1].size(), 4);
|
||||||
|
BOOST_CHECK_EQUAL(collapsed.unpacked_path_segments[0][0].turn_via_node, 2);
|
||||||
|
BOOST_CHECK_EQUAL(collapsed.unpacked_path_segments[0][1].turn_via_node, 1);
|
||||||
|
BOOST_CHECK_EQUAL(collapsed.unpacked_path_segments[1][0].turn_via_node, 1);
|
||||||
|
BOOST_CHECK_EQUAL(collapsed.unpacked_path_segments[1][1].turn_via_node, 5);
|
||||||
|
BOOST_CHECK_EQUAL(collapsed.unpacked_path_segments[1][2].turn_via_node, 3);
|
||||||
|
BOOST_CHECK_EQUAL(collapsed.unpacked_path_segments[1][3].turn_via_node, 4);
|
||||||
|
}
|
||||||
|
|
||||||
|
BOOST_AUTO_TEST_CASE(two_legs_to_two_legs)
|
||||||
|
{
|
||||||
|
PathData pathy{2, 17, false, 2, 3, 4, 5, 0, {}, 4, 2, {}, 2, {1.0}, {1.0}, false};
|
||||||
|
PathData kathy{1, 16, false, 1, 2, 3, 4, 1, {}, 3, 1, {}, 1, {2.0}, {3.0}, false};
|
||||||
|
PathData cathy{3, 16, false, 1, 2, 3, 4, 1, {}, 3, 1, {}, 1, {2.0}, {3.0}, false};
|
||||||
|
PhantomNode node_1;
|
||||||
|
PhantomNode node_2;
|
||||||
|
PhantomNode node_3;
|
||||||
|
node_1.forward_segment_id = {1, true};
|
||||||
|
node_2.forward_segment_id = {6, true};
|
||||||
|
node_3.forward_segment_id = {12, true};
|
||||||
|
InternalRouteResult two_leg_result;
|
||||||
|
two_leg_result.unpacked_path_segments = {{pathy, kathy}, {kathy, cathy}};
|
||||||
|
two_leg_result.segment_end_coordinates = {PhantomNodes{node_1, node_2},
|
||||||
|
PhantomNodes{node_2, node_3}};
|
||||||
|
two_leg_result.source_traversed_in_reverse = {true, false};
|
||||||
|
two_leg_result.target_traversed_in_reverse = {true, false};
|
||||||
|
two_leg_result.shortest_path_weight = 80;
|
||||||
|
|
||||||
|
auto collapsed = CollapseInternalRouteResult(two_leg_result, {true, true, true});
|
||||||
|
BOOST_CHECK_EQUAL(collapsed.unpacked_path_segments.size(), 2);
|
||||||
|
BOOST_CHECK_EQUAL(collapsed.segment_end_coordinates.size(), 2);
|
||||||
|
BOOST_CHECK_EQUAL(collapsed.segment_end_coordinates[0].source_phantom.forward_segment_id.id, 1);
|
||||||
|
BOOST_CHECK_EQUAL(collapsed.segment_end_coordinates[0].target_phantom.forward_segment_id.id, 6);
|
||||||
|
BOOST_CHECK_EQUAL(collapsed.segment_end_coordinates[1].source_phantom.forward_segment_id.id, 6);
|
||||||
|
BOOST_CHECK_EQUAL(collapsed.segment_end_coordinates[1].target_phantom.forward_segment_id.id,
|
||||||
|
12);
|
||||||
|
BOOST_CHECK_EQUAL(collapsed.unpacked_path_segments[0].size(), 2);
|
||||||
|
BOOST_CHECK_EQUAL(collapsed.unpacked_path_segments[1].size(), 2);
|
||||||
|
BOOST_CHECK_EQUAL(collapsed.unpacked_path_segments[0][0].turn_via_node, 2);
|
||||||
|
BOOST_CHECK_EQUAL(collapsed.unpacked_path_segments[0][1].turn_via_node, 1);
|
||||||
|
BOOST_CHECK_EQUAL(collapsed.unpacked_path_segments[1][0].turn_via_node, 1);
|
||||||
|
BOOST_CHECK_EQUAL(collapsed.unpacked_path_segments[1][1].turn_via_node, 3);
|
||||||
|
}
|
||||||
|
|
||||||
|
BOOST_AUTO_TEST_SUITE_END()
|
||||||
@@ -13,6 +13,14 @@ using Latitude = osrm::util::FloatLatitude;
|
|||||||
using Location = osrm::util::Coordinate;
|
using Location = osrm::util::Coordinate;
|
||||||
using Locations = std::vector<Location>;
|
using Locations = std::vector<Location>;
|
||||||
|
|
||||||
|
inline Locations get_split_trace_locations()
|
||||||
|
{
|
||||||
|
return {{Longitude{7.420202}, Latitude{43.732274}},
|
||||||
|
{Longitude{7.422369}, Latitude{43.732282}},
|
||||||
|
{Longitude{7.421511}, Latitude{43.734181}},
|
||||||
|
{Longitude{7.421489}, Latitude{43.736553}}};
|
||||||
|
}
|
||||||
|
|
||||||
inline Location get_dummy_location()
|
inline Location get_dummy_location()
|
||||||
{
|
{
|
||||||
return {osrm::util::FloatLongitude{7.437069}, osrm::util::FloatLatitude{43.749249}};
|
return {osrm::util::FloatLongitude{7.437069}, osrm::util::FloatLatitude{43.749249}};
|
||||||
|
|||||||
@@ -64,4 +64,61 @@ BOOST_AUTO_TEST_CASE(test_match)
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
BOOST_AUTO_TEST_CASE(test_match_split)
|
||||||
|
{
|
||||||
|
using namespace osrm;
|
||||||
|
|
||||||
|
auto osrm = getOSRM(OSRM_TEST_DATA_DIR "/ch/monaco.osrm");
|
||||||
|
|
||||||
|
MatchParameters params;
|
||||||
|
params.coordinates = get_split_trace_locations();
|
||||||
|
params.timestamps = {1, 2, 1700, 1800};
|
||||||
|
|
||||||
|
json::Object result;
|
||||||
|
|
||||||
|
const auto rc = osrm.Match(params, result);
|
||||||
|
|
||||||
|
BOOST_CHECK(rc == Status::Ok || rc == Status::Error);
|
||||||
|
const auto code = result.values.at("code").get<json::String>().value;
|
||||||
|
BOOST_CHECK_EQUAL(code, "Ok");
|
||||||
|
|
||||||
|
const auto &tracepoints = result.values.at("tracepoints").get<json::Array>().values;
|
||||||
|
BOOST_CHECK_EQUAL(tracepoints.size(), params.coordinates.size());
|
||||||
|
|
||||||
|
const auto &matchings = result.values.at("matchings").get<json::Array>().values;
|
||||||
|
const auto &number_of_matchings = matchings.size();
|
||||||
|
BOOST_CHECK_EQUAL(number_of_matchings, 2);
|
||||||
|
std::size_t current_matchings_index = 0, expected_waypoint_index = 0;
|
||||||
|
for (const auto &waypoint : tracepoints)
|
||||||
|
{
|
||||||
|
if (waypoint.is<mapbox::util::recursive_wrapper<util::json::Object>>())
|
||||||
|
{
|
||||||
|
BOOST_CHECK(waypoint_check(waypoint));
|
||||||
|
const auto &waypoint_object = waypoint.get<json::Object>();
|
||||||
|
const auto matchings_index =
|
||||||
|
waypoint_object.values.at("matchings_index").get<json::Number>().value;
|
||||||
|
const auto waypoint_index =
|
||||||
|
waypoint_object.values.at("waypoint_index").get<json::Number>().value;
|
||||||
|
const auto &route_legs = matchings[matchings_index]
|
||||||
|
.get<json::Object>()
|
||||||
|
.values.at("legs")
|
||||||
|
.get<json::Array>()
|
||||||
|
.values;
|
||||||
|
|
||||||
|
BOOST_CHECK_LT(matchings_index, number_of_matchings);
|
||||||
|
|
||||||
|
expected_waypoint_index =
|
||||||
|
(current_matchings_index != matchings_index) ? 0 : expected_waypoint_index;
|
||||||
|
BOOST_CHECK_EQUAL(waypoint_index, expected_waypoint_index);
|
||||||
|
|
||||||
|
current_matchings_index = matchings_index;
|
||||||
|
++expected_waypoint_index;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
BOOST_CHECK(waypoint.is<json::Null>());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
BOOST_AUTO_TEST_SUITE_END()
|
BOOST_AUTO_TEST_SUITE_END()
|
||||||
|
|||||||
@@ -44,7 +44,7 @@ class MockScriptingEnvironment : public extractor::ScriptingEnvironment
|
|||||||
{
|
{
|
||||||
}
|
}
|
||||||
|
|
||||||
bool HasLocationDependentData() const { return false; };
|
bool HasLocationDependentData() const override { return false; };
|
||||||
};
|
};
|
||||||
|
|
||||||
} // namespace test
|
} // namespace test
|
||||||
|
|||||||
@@ -555,6 +555,22 @@ BOOST_AUTO_TEST_CASE(valid_match_urls)
|
|||||||
CHECK_EQUAL_RANGE(reference_2.radiuses, result_2->radiuses);
|
CHECK_EQUAL_RANGE(reference_2.radiuses, result_2->radiuses);
|
||||||
CHECK_EQUAL_RANGE(reference_2.approaches, result_2->approaches);
|
CHECK_EQUAL_RANGE(reference_2.approaches, result_2->approaches);
|
||||||
CHECK_EQUAL_RANGE(reference_2.coordinates, result_2->coordinates);
|
CHECK_EQUAL_RANGE(reference_2.coordinates, result_2->coordinates);
|
||||||
|
|
||||||
|
std::vector<util::Coordinate> coords_2 = {{util::FloatLongitude{1}, util::FloatLatitude{2}},
|
||||||
|
{util::FloatLongitude{3}, util::FloatLatitude{4}},
|
||||||
|
{util::FloatLongitude{5}, util::FloatLatitude{6}}};
|
||||||
|
|
||||||
|
MatchParameters reference_3{};
|
||||||
|
reference_3.coordinates = coords_2;
|
||||||
|
reference_3.waypoints = {0, 2};
|
||||||
|
auto result_3 = parseParameters<MatchParameters>("1,2;3,4;5,6?waypoints=0;2");
|
||||||
|
BOOST_CHECK(result_3);
|
||||||
|
CHECK_EQUAL_RANGE(reference_3.waypoints, result_3->waypoints);
|
||||||
|
CHECK_EQUAL_RANGE(reference_3.timestamps, result_3->timestamps);
|
||||||
|
CHECK_EQUAL_RANGE(reference_3.bearings, result_3->bearings);
|
||||||
|
CHECK_EQUAL_RANGE(reference_3.radiuses, result_3->radiuses);
|
||||||
|
CHECK_EQUAL_RANGE(reference_3.approaches, result_3->approaches);
|
||||||
|
CHECK_EQUAL_RANGE(reference_3.coordinates, result_3->coordinates);
|
||||||
}
|
}
|
||||||
|
|
||||||
BOOST_AUTO_TEST_CASE(invalid_match_urls)
|
BOOST_AUTO_TEST_CASE(invalid_match_urls)
|
||||||
@@ -571,6 +587,15 @@ BOOST_AUTO_TEST_CASE(invalid_match_urls)
|
|||||||
BOOST_CHECK(reference_1.radiuses != result_1->radiuses);
|
BOOST_CHECK(reference_1.radiuses != result_1->radiuses);
|
||||||
CHECK_EQUAL_RANGE(reference_1.approaches, result_1->approaches);
|
CHECK_EQUAL_RANGE(reference_1.approaches, result_1->approaches);
|
||||||
CHECK_EQUAL_RANGE(reference_1.coordinates, result_1->coordinates);
|
CHECK_EQUAL_RANGE(reference_1.coordinates, result_1->coordinates);
|
||||||
|
|
||||||
|
std::vector<util::Coordinate> coords_2 = {{util::FloatLongitude{1}, util::FloatLatitude{2}},
|
||||||
|
{util::FloatLongitude{3}, util::FloatLatitude{4}}};
|
||||||
|
|
||||||
|
MatchParameters reference_2{};
|
||||||
|
reference_2.coordinates = coords_2;
|
||||||
|
BOOST_CHECK_EQUAL(testInvalidOptions<MatchParameters>("1,2;3,4?waypoints=0,4"), 19UL);
|
||||||
|
BOOST_CHECK_EQUAL(testInvalidOptions<MatchParameters>("1,2;3,4?waypoints=x;4"), 18UL);
|
||||||
|
BOOST_CHECK_EQUAL(testInvalidOptions<MatchParameters>("1,2;3,4?waypoints=0;3.5"), 21UL);
|
||||||
}
|
}
|
||||||
|
|
||||||
BOOST_AUTO_TEST_CASE(valid_nearest_urls)
|
BOOST_AUTO_TEST_CASE(valid_nearest_urls)
|
||||||
|
|||||||
@@ -1,4 +1,4 @@
|
|||||||
#define BOOST_TEST_MODULE customizer tests
|
#define BOOST_TEST_MODULE updater tests
|
||||||
|
|
||||||
#include <boost/test/unit_test.hpp>
|
#include <boost/test/unit_test.hpp>
|
||||||
|
|
||||||
|
|||||||
Reference in New Issue
Block a user