Support snapping to multiple ways at an input location (#5953)

This PR improves routing results by adding support for snapping to
multiple ways at input locations.

This means all edges at the snapped location can act as source/target
candidates for routing search, ensuring we always find the best route,
and not the one dependent on the edge selected.
This commit is contained in:
Michael Bell 2022-08-27 11:36:20 +01:00 committed by GitHub
parent bb18a2b428
commit d74e7b66bd
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
59 changed files with 2820 additions and 1964 deletions

View File

@ -49,6 +49,7 @@
- FIXED: Completed support for no_entry and no_exit turn restrictions. [#5988](https://github.com/Project-OSRM/osrm-backend/pull/5988) - FIXED: Completed support for no_entry and no_exit turn restrictions. [#5988](https://github.com/Project-OSRM/osrm-backend/pull/5988)
- ADDED: Add support for non-round-trips with a single fixed endpoint. [#6050](https://github.com/Project-OSRM/osrm-backend/pull/6050) - ADDED: Add support for non-round-trips with a single fixed endpoint. [#6050](https://github.com/Project-OSRM/osrm-backend/pull/6050)
- FIXED: Improvements to maneuver override processing [#6125](https://github.com/Project-OSRM/osrm-backend/pull/6125) - FIXED: Improvements to maneuver override processing [#6125](https://github.com/Project-OSRM/osrm-backend/pull/6125)
- ADDED: Support snapping to multiple ways at an input location. [#5953](https://github.com/Project-OSRM/osrm-backend/pull/5953)
# 5.26.0 # 5.26.0
- Changes from 5.25.0 - Changes from 5.25.0

View File

@ -28,7 +28,7 @@ Feature: Bicycle - Route around alleys
When I route I should get When I route I should get
| from | to | a:nodes | weight | # | | from | to | a:nodes | weight | # |
| a | f | 1:2:3:6 | 200.4 | Avoids d,e,f | | a | f | 1:2:3:6 | 196.2 | Avoids d,e,f |
| a | e | 1:2:5 | 176.4 | Take the alley b,e if neccessary | | a | e | 1:2:5 | 172.2 | Take the alley b,e if neccessary |
| d | f | 4:1:2:3:6 | 252.6 | Avoids the alley d,e,f | | d | f | 4:1:2:3:6 | 248.4 | Avoids the alley d,e,f |

View File

@ -8,7 +8,7 @@ Feature: Car - Destination only, no passing through
Given the node map Given the node map
""" """
a e a e
b c d b1 c 2d
x y x y
""" """
@ -23,19 +23,19 @@ Feature: Car - Destination only, no passing through
When I route I should get When I route I should get
| from | to | route | | from | to | route |
| a | b | ab,ab | | a | b | ab,ab |
| a | c | ab,bcd | | a | c | ab,bcd,bcd |
| a | d | ab,bcd,bcd | | a | 2 | ab,bcd,bcd |
| a | e | axye,axye | | a | e | axye,axye |
| e | d | de,de | | e | d | de,de |
| e | c | de,bcd | | e | c | de,bcd,bcd |
| e | b | de,bcd,bcd | | e | 1 | de,bcd,bcd |
| e | a | axye,axye | | e | a | axye,axye |
Scenario: Car - Destination only street Scenario: Car - Destination only street
Given the node map Given the node map
""" """
a e a e
b c d b1 c 2d
x y x y
""" """
@ -51,12 +51,12 @@ Feature: Car - Destination only, no passing through
When I route I should get When I route I should get
| from | to | route | | from | to | route |
| a | b | ab,ab | | a | b | ab,ab |
| a | c | ab,bc | | a | c | ab,bc,bc |
| a | d | ab,cd | | a | 2 | ab,bc,cd |
| a | e | axye,axye | | a | e | axye,axye |
| e | d | de,de | | e | d | de,de |
| e | c | de,cd | | e | c | de,cd,cd |
| e | b | de,bc | | e | 1 | de,cd,bc |
| e | a | axye,axye | | e | a | axye,axye |
Scenario: Car - Routing inside a destination only area Scenario: Car - Routing inside a destination only area
@ -117,6 +117,7 @@ Feature: Car - Destination only, no passing through
+ \ + \
+ | + |
d | d |
1 |
\___e \___e
""" """
@ -129,7 +130,7 @@ Feature: Car - Destination only, no passing through
When I route I should get When I route I should get
| from | to | route | | from | to | route |
| e | a | acbe,acbe | | e | a | acbe,acbe |
| d | a | de,acbe,acbe | | 1 | a | de,acbe,acbe |
| c | d | cd,cd | | c | d | cd,cd |
Scenario: Car - Routing through a parking lot tagged access=destination,service Scenario: Car - Routing through a parking lot tagged access=destination,service

View File

@ -411,7 +411,7 @@ Feature: Car - Turn restrictions
y y
i j f b x a e g h i j f b x a e g h
c d c1 d
""" """
And the ways And the ways
@ -438,7 +438,7 @@ Feature: Car - Turn restrictions
When I route I should get When I route I should get
| from | to | route | | from | to | route |
| e | f | ae,xa,bx,fb,fb | | e | f | ae,xa,bx,fb,fb |
| c | f | dc,da,ae,ge,hg,hg,ge,ae,xa,bx,fb,fb | | 1 | f | dc,da,ae,ge,hg,hg,ge,ae,xa,bx,fb,fb |
| d | f | da,ae,ge,hg,hg,ge,ae,xa,bx,fb,fb | | d | f | da,ae,ge,hg,hg,ge,ae,xa,bx,fb,fb |
@except @except

View File

@ -332,10 +332,11 @@ Feature: Merge Segregated Roads
| |
.b. .b.
c h c h
1 |
| 4
| | | |
| | 2 |
1 2 | 3
| |
d g d g
'e' 'e'
| |
@ -356,11 +357,11 @@ Feature: Merge Segregated Roads
When I route I should get When I route I should get
| waypoints | turns | route | intersections | | waypoints | turns | route | intersections |
| a,f | depart,arrive | road,road | true:180,false:0 true:180,false:0 true:180;true:0 | | a,f | depart,arrive | road,road | true:180,false:0 true:180,false:0 true:180;true:0 |
| c,f | depart,arrive | bridge,road | true:180,false:0 true:180;true:0 |
| 1,f | depart,arrive | bridge,road | true:180,false:0 true:180;true:0 | | 1,f | depart,arrive | bridge,road | true:180,false:0 true:180;true:0 |
| 2,f | depart,arrive | bridge,road | true:180,false:0 true:180;true:0 |
| f,a | depart,arrive | road,road | true:0,true:0 false:180,true:0 false:180;true:180 | | f,a | depart,arrive | road,road | true:0,true:0 false:180,true:0 false:180;true:180 |
| g,a | depart,arrive | bridge,road | true:0,true:0 false:180;true:180 | | 3,a | depart,arrive | bridge,road | true:0,true:0 false:180;true:180 |
| 2,a | depart,arrive | bridge,road | true:0,true:0 false:180;true:180 | | 4,a | depart,arrive | bridge,road | true:0,true:0 false:180;true:180 |
@negative @negative
Scenario: Traffic Circle Scenario: Traffic Circle

View File

@ -67,10 +67,10 @@ Feature: Compass bearing
Scenario: Bearing in a roundabout Scenario: Bearing in a roundabout
Given the node map Given the node map
""" """
k d c j k d 1c j
e b e b
f a f a
l g h i l g2 h i
""" """
And the ways And the ways
@ -94,8 +94,8 @@ Feature: Compass bearing
When I route I should get When I route I should get
| from | to | route | bearing | | from | to | route | bearing |
| c | b | cd,de,ef,fg,gh,ha,ab,ab | 0->270,270->225,225->180,180->135,135->90,90->45,45->0,0->0 | | 1 | b | cd,de,ef,fg,gh,ha,ab,ab | 0->270,270->225,225->180,180->135,135->90,90->45,45->0,0->0 |
| g | f | gh,ha,ab,bc,cd,de,ef,ef | 0->90,90->45,45->0,0->315,315->270,270->225,225->180,180->0 | | 2 | f | gh,ha,ab,bc,cd,de,ef,ef | 0->90,90->45,45->0,0->315,315->270,270->225,225->180,180->0 |
Scenario: Bearing should stay constant when zig-zagging Scenario: Bearing should stay constant when zig-zagging
Given the node map Given the node map

View File

@ -589,12 +589,12 @@ Feature: Basic Distance Matrix
When I request a travel distance matrix I should get When I request a travel distance matrix I should get
| | a | b | c | d | e | f | | | a | b | c | d | e | f |
| a | 0 | 100 | 300 | 650 | 1934.5 | 1534.6 | | a | 0 | 100 | 300 | 650 | 660.5 | 1534.6 |
| b | 760.6 | 0 | 200 | 550.1 | 1834.6 | 1434.6 | | b | 760.6 | 0 | 200 | 550.1 | 560.6 | 1434.6 |
| c | 560.6 | 660.5 | 0 | 350 | 1634.6 | 1234.6 | | c | 560.6 | 660.5 | 0 | 350 | 360.5 | 1234.6 |
| d | 1484.6 | 1584.5| 1784.5 | 0 | 1284.5 | 884.6 | | d | 1484.6 | 1584.5| 1645.1 | 0 | 1284.5 | 884.6 |
| e | 200 | 300 | 500 | 710.6 | 0 | 1595.2 | | e | 200 | 300 | 360.5 | 710.6 | 0 | 1595.2 |
| f | 600 | 699.9 | 899.9 | 1110.5 | 399.9 | 0 | | f | 600 | 699.9 | 760.5 | 884.6 | 399.9 | 0 |
Scenario: Testbot - Filling in noroutes with estimates (defaults to input coordinate location) Scenario: Testbot - Filling in noroutes with estimates (defaults to input coordinate location)
@ -727,4 +727,3 @@ Feature: Basic Distance Matrix
| 1 | 0 | 1000.1 | 1400.1 | | 1 | 0 | 1000.1 | 1400.1 |
| 2 | 1000.1 | 0 | 400 | | 2 | 1000.1 | 0 | 400 |
| 3 | 1400.1 | 400 | 0 | | 3 | 1400.1 | 400 | 0 |

View File

@ -491,18 +491,18 @@ Feature: Basic Duration Matrix
When I route I should get When I route I should get
| from | to | route | distance | time | weight | | from | to | route | distance | time | weight |
| a | c | ac,ac | 200m | 5s | 5 | | a | c | ac,ac | 200m | 1s | 1 |
When I request a travel time matrix I should get When I request a travel time matrix I should get
| | a | b | c | d | | | a | b | c | d |
| a | 0 | 1 | 5 | 10 | | a | 0 | 1 | 1 | 6 |
When I request a travel time matrix I should get When I request a travel time matrix I should get
| | a | | | a |
| a | 0 | | a | 0 |
| b | 1 | | b | 1 |
| c | 15 | | c | 1 |
| d | 10 | | d | 6 |
Scenario: Testbot - OneToMany vs ManyToOne Scenario: Testbot - OneToMany vs ManyToOne
Given the node map Given the node map

View File

@ -0,0 +1,629 @@
Feature: Snapping at intersections
Background:
# Use turnbot so that we can validate when we are
# snapping to one of many potential candidate ways
Given the profile "turnbot"
# https://github.com/Project-OSRM/osrm-backend/issues/4465
Scenario: Snapping source to intersection with one-way roads
Given the node map
"""
a e c
\ | /
d
1
"""
And the ways
| nodes | oneway |
| da | yes |
| dc | yes |
| de | yes |
When I route I should get
| from | to | route | time |
| 1 | e | de,de | 20s |
| 1 | a | da,da | 28.3s |
| 1 | c | dc,dc | 28.3s |
When I request a travel time matrix I should get
| | a | c | e |
| 1 | 28.3 | 28.3 | 20 |
Scenario: Snapping destination to intersection with one-way roads
Given the node map
"""
a e c
\ | /
d
1
"""
And the ways
| nodes | oneway |
| da | -1 |
| dc | -1 |
| de | -1 |
When I route I should get
| from | to | route | time |
| e | 1 | de,de | 20s |
| a | 1 | da,da | 28.3s |
| c | 1 | dc,dc | 28.3s |
When I request a travel time matrix I should get
| | 1 |
| a | 28.3 |
| c | 28.3 |
| e | 20 |
Scenario: Snapping to intersection with bi-directional roads
Given the node map
"""
a e
| /
d---c
1
"""
And the ways
| nodes |
| ad |
| ed |
| dc |
When I route I should get
| from | to | route | time | weight |
| 1 | c | dc,dc | 20s | 20 |
| 1 | a | ad,ad | 20s | 20 |
| 1 | e | ed,ed | 28.3s | 28.3 |
| c | 1 | dc,dc | 20s | 20 |
| a | 1 | ad,ad | 20s | 20 |
| e | 1 | ed,ed | 28.3s | 28.3 |
When I request a travel time matrix I should get
| | a | c | e |
| 1 | 20 | 20 | 28.3 |
When I request a travel time matrix I should get
| | 1 |
| a | 20 |
| c | 20 |
| e | 28.3 |
Scenario: Snapping at compressible node
Given the node map
"""
a---b---c
"""
And the ways
| nodes |
| abc |
When I route I should get
| from | to | route | time | weight |
| b | c | abc,abc | 20s | 20 |
| b | a | abc,abc | 20s | 20 |
| a | b | abc,abc | 20s | 20 |
| c | b | abc,abc | 20s | 20 |
Scenario: Snapping at compressible node with traffic lights
Given the node map
"""
a---b---c
"""
And the ways
| nodes |
| abc |
# Turnbot will use the turn penalty instead of traffic penalty.
# We do this to induce a penalty between two edges of the same
# segment.
And the nodes
| node | highway |
| b | traffic_signals |
# Snaps to first edge in forward direction
When I route I should get
| from | to | route | time | weight |
| b | c | abc,abc | 40s | 40 |
| b | a | abc,abc | 20s | 20 |
| a | b | abc,abc | 20s | 20 |
| c | b | abc,abc | 40s | 40 |
Scenario: Snapping at compressible node traffic lights, one-way
Given the node map
"""
a-->b-->c
"""
And the ways
| nodes | oneway |
| abc | yes |
# Turnbot will use the turn penalty instead of traffic penalty.
# We do this to induce a penalty between two edges of the same
# segment.
And the nodes
| node | highway |
| b | traffic_signals |
# Snaps to first edge in forward direction
When I route I should get
| from | to | route | time | weight |
| b | c | abc,abc | 40s | 40 |
| a | b | abc,abc | 20s | 20 |
When I route I should get
| from | to | code |
| b | a | NoRoute |
| c | b | NoRoute |
Scenario: Snapping at compressible node traffic lights, reverse one-way
Given the node map
"""
a<--b<--c
"""
And the ways
| nodes | oneway |
| abc | -1 |
# Turnbot will use the turn penalty instead of traffic penalty.
# We do this to induce a penalty between two edges of the same
# segment.
And the nodes
| node | highway |
| b | traffic_signals |
# Snaps to first edge in forward direction - as this is one-way,
# the forward direction has changed.
When I route I should get
| from | to | route | time | weight |
| b | a | abc,abc | 40s | 40 |
| c | b | abc,abc | 20s | 20 |
When I route I should get
| from | to | code |
| b | c | NoRoute |
| a | b | NoRoute |
Scenario: Snapping at traffic lights, reverse disabled
Given the node map
"""
a-->b-->c
"""
And the ways
| nodes |
| abc |
And the contract extra arguments "--segment-speed-file {speeds_file}"
And the customize extra arguments "--segment-speed-file {speeds_file}"
And the speed file
"""
2,1,0
3,2,0
"""
# Turnbot will use the turn penalty instead of traffic penalty.
# We do this to induce a penalty between two edges of the same
# segment.
And the nodes
| node | highway |
| b | traffic_signals |
# Snaps to first edge in forward direction.
When I route I should get
| from | to | route | time | weight |
| b | c | abc,abc | 40s | 40 |
| a | b | abc,abc | 20s | 20 |
When I route I should get
| from | to | code |
| b | a | NoRoute |
| c | b | NoRoute |
Scenario: Snapping at traffic lights, forward disabled
Given the node map
"""
a<--b<--c
"""
And the ways
| nodes |
| abc |
And the contract extra arguments "--segment-speed-file {speeds_file}"
And the customize extra arguments "--segment-speed-file {speeds_file}"
And the speed file
"""
1,2,0
2,3,0
"""
# Turnbot will use the turn penalty instead of traffic penalty.
# We do this to induce a penalty between two edges of the same
# segment.
And the nodes
| node | highway |
| b | traffic_signals |
# Forward direction is disabled, still snaps to first edge in forward direction
When I route I should get
| from | to | route | time | weight |
| b | a | abc,abc | 20s | 20 |
| c | b | abc,abc | 40s | 40 |
When I route I should get
| from | to | code |
| b | c | NoRoute |
| a | b | NoRoute |
Scenario: Snap to target node with next section of segment blocked
Given the node map
"""
a-->b---c---d<--e
"""
And the ways
| nodes |
| abc |
| cde |
And the contract extra arguments "--segment-speed-file {speeds_file}"
And the customize extra arguments "--segment-speed-file {speeds_file}"
And the speed file
"""
2,1,0
4,5,0
"""
When I route I should get
| from | to | route | time | weight |
| a | d | abc,cde,cde | 60s | 60 |
| e | b | cde,abc,abc | 60s | 60 |
When I route I should get
| from | to | code |
| a | e | NoRoute |
| e | a | NoRoute |
Scenario: Snapping to source node with previous section of segment blocked
Given the node map
"""
a<--b---c---d-->e
"""
And the ways
| nodes |
| abc |
| cde |
And the contract extra arguments "--segment-speed-file {speeds_file}"
And the customize extra arguments "--segment-speed-file {speeds_file}"
And the speed file
"""
1,2,0
5,4,0
"""
When I route I should get
| from | to | code |
| a | e | NoRoute |
| b | e | NoRoute |
| e | a | NoRoute |
| d | a | NoRoute |
Scenario: Only snaps to one of many equidistant nearest locations
Given the node map
"""
b-------c
| |
| |
a 1 d
"""
And the ways
| nodes |
| ab |
| bc |
| cd |
When I route I should get
| from | to | route | time | weight |
| 1 | b | ab,ab | 30s | 30 |
| 1 | c | ab,bc,bc | 80s +-1 | 80 +-1 |
Scenario: Snaps to alternative big SCC candidate if nearest candidates are not strongly connected
Given the node map
"""
1
g---h---i
a-----b-----c
|
f-----e-----d
j---k---l
2
"""
Given the extract extra arguments "--small-component-size=4"
And the ways
| nodes |
| abc |
| cd |
| fed |
| ghi |
| jkl |
# As forward direction is disabled...
When I route I should get
| from | to | route | time | weight | locations |
| 1 | 2 | abc,cd,fed,fed | 100s +-1 | 100 +-1 | b,c,d,e |
Scenario: Can use big or small SCC nearest candidates if at same location
Given the node map
"""
1
a-----b-----c
| |
g |
|
f-----e-----d
"""
Given the extract extra arguments "--small-component-size=4"
And the ways
| nodes | oneway |
| ab | no |
| bc | no |
| cd | no |
| fed | no |
| bg | yes | # small SCC
And the relations
| type | way:from | way:to | node:via | restriction |
| restriction | ab | bg | b | no_right_turn |
| restriction | bc | bg | b | no_left_turn |
When I route I should get
| from | to | route | time | weight | locations |
| 1 | g | bg,bg | 20s | 20 | b,g |
| 1 | e | bc,cd,fed,fed | 120s +-1 | 120 +-1 | b,c,d,e |
Scenario: Using small SCC candidates when at same location as big SCC alternatives is not supported
Given the node map
"""
1
g---h---i
a-----b-----c
| |
| |
m |
f-----e-----d
j---k---l
2
"""
Given the extract extra arguments "--small-component-size=4"
And the ways
| nodes | oneway |
| ab | no |
| bc | no |
| cd | no |
| fed | no |
| ghi | no |
| jkl | no |
| bm | yes | # small SCC
And the relations
| type | way:from | way:to | node:via | restriction |
| restriction | ab | bm | b | no_right_turn |
| restriction | bc | bm | b | no_left_turn |
When I route I should get
| from | to | route | time | weight | locations |
| 1 | 2 | bc,cd,fed,fed | 120s +-1 | 120 +-1 | b,c,d,e |
| 1 | m | bc,cd,fed,fed | 120s +-1 | 120 +-1 | b,c,d,e |
Scenario: Shortest via path with continuation, simple loop
Given the node map
"""
a---b
"""
And the ways
| nodes |
| ab |
When I route I should get
| waypoints | route | time | weight |
| a,b,a | ab,ab,ab,ab | 60s | 60 |
Scenario: Shortest via path with uturns, simple loop
Given the node map
"""
a---b
"""
Given the query options
| continue_straight | false |
And the ways
| nodes |
| ab |
# Does not pay the cost of the turn
When I route I should get
| waypoints | route | time | weight |
| a,b,a | ab,ab,ab,ab | 40s | 40 |
Scenario: Shortest path with multiple endpoint snapping candidates
Given the node map
"""
b
c
a d f
e
"""
And the ways
| nodes | oneway |
| ab | no |
| ac | no |
| ad | no |
| ae | no |
| bf | no |
| cf | yes |
| df | yes |
| ef | no |
When I route I should get
| from | to | route | time | weight |
| a | f | ad,df,df | 40s | 40 |
| f | a | ef,ae,ae | 66.6s | 66.6 |
When I request a travel time matrix I should get
| | a | f |
| a | 0 | 40 |
| f | 66.6 | 0 |
Scenario: Shortest via path with continuation, multiple waypoint snapping candidates
Given the node map
"""
b g
c h
a d f i
k
e j
"""
And the ways
| nodes | oneway |
| ab | no |
| ac | no |
| ad | no |
| ae | no |
| bf | no |
| cf | yes |
| df | yes |
| ef | no |
| fg | no |
| fh | -1 |
| fi | -1 |
| fj | no |
| gk | no |
| hk | no |
| ik | no |
| kj | no |
And the relations
| type | way:from | way:to | node:via | restriction |
| restriction | df | fg | f | only_left_turn |
| restriction | fi | bf | f | only_right_turn |
# Longer routes can take different paths from sub-routes
When I route I should get
| waypoints | route | time | weight |
| a,f | ad,df,df | 40s | 40 |
| f,k | fj,kj,kj | 65.6s | 65.6 |
| a,f,k | ac,cf,cf,fj,kj,kj | 132.8s | 132.8 |
| k,f | ik,fi,fi | 54.3s | 54.3 |
| f,a | ef,ae,ae | 66.6s | 66.6 |
| k,f,a | kj,fj,fj,ef,ae,ae | 141.4s | 141.4 |
When I request a travel time matrix I should get
| | a | f | k |
| a | 0 | 40 | 132.8 |
| f | 66.6 | 0 | 65.6 |
| k | 141.4 | 54.3 | 0 |
Scenario: Shortest via path with uturns, multiple waypoint snapping candidates
Given the node map
"""
b g
c h
a d f i
k
e j
"""
Given the query options
| continue_straight | false |
And the ways
| nodes | oneway |
| ab | no |
| ac | no |
| ad | no |
| ae | no |
| bf | no |
| cf | yes |
| df | yes |
| ef | no |
| fg | no |
| fh | -1 |
| fi | -1 |
| fj | no |
| gk | no |
| hk | no |
| ik | no |
| kj | no |
And the relations
| type | way:from | way:to | node:via | restriction |
| restriction | df | fg | f | only_left_turn |
| restriction | fi | bf | f | only_right_turn |
# Longer routes use same path as sub-routes
When I route I should get
| waypoints | route | time | weight |
| a,f | ad,df,df | 40s | 40 |
| f,k | fj,kj,kj | 65.6s | 65.6 |
| a,f,k | ad,df,df,fj,kj,kj | 105.6s | 105.6 |
| k,f | ik,fi,fi | 54.3s | 54.3 |
| f,a | ef,ae,ae | 66.6s | 66.6 |
| k,f,a | ik,fi,fi,ef,ae,ae | 120.9s | 120.9 |

View File

@ -47,7 +47,7 @@ Feature: Traffic - turn penalties applied to turn onto which a phantom node snap
| 1 | e | ab,be,be | 36 km/h | 30s +-1 | | 1 | e | ab,be,be | 36 km/h | 30s +-1 |
| b | f | bc,cf,cf | 36 km/h | 40s +-1 | | b | f | bc,cf,cf | 36 km/h | 40s +-1 |
| 2 | f | bc,cf,cf | 36 km/h | 30s +-1 | | 2 | f | bc,cf,cf | 36 km/h | 30s +-1 |
| c | g | cd,dg,dg | 144 km/h | 10s +-1 | | c | g | cd,dg,dg | 72 km/h | 20s +-1 |
| 3 | g | cd,dg,dg | 54 km/h | 20s +-1 | | 3 | g | cd,dg,dg | 54 km/h | 20s +-1 |
Scenario: Weighting based on turn penalty file with weights Scenario: Weighting based on turn penalty file with weights
@ -65,5 +65,5 @@ Feature: Traffic - turn penalties applied to turn onto which a phantom node snap
| 1 | e | ab,be,be | 36 km/h | 30s +-1 | 6.8,20,0 | | 1 | e | ab,be,be | 36 km/h | 30s +-1 | 6.8,20,0 |
| b | f | bc,cf,cf | 36 km/h | 40s +-1 | 20,20,0 | | b | f | bc,cf,cf | 36 km/h | 40s +-1 | 20,20,0 |
| 2 | f | bc,cf,cf | 36 km/h | 30s +-1 | 10.1,20,0 | | 2 | f | bc,cf,cf | 36 km/h | 30s +-1 | 10.1,20,0 |
| c | g | cd,dg,dg | 144 km/h | 10s +-1 | 120.8,20,0 | | c | g | cd,dg,dg | 72 km/h | 20s +-1 | 120.8,20,0 |
| 3 | g | cd,dg,dg | 54 km/h | 20s +-1 | 110.9,20,0 | | 3 | g | cd,dg,dg | 54 km/h | 20s +-1 | 110.9,20,0 |

View File

@ -281,7 +281,7 @@ Feature: Weight tests
When I route I should get When I route I should get
| waypoints | route | distance | weights | times | | waypoints | route | distance | weights | times |
| a,c | , | 40m +-.1 | 5.12,0 | 290s,0s | | a,c | , | 40m +-.1 | 2.22,0 | 200s,0s |
| a,e | ,, | 60m +-.1 | 5.12,1.11,0 | 290s,100s,0s | | a,e | ,, | 60m +-.1 | 5.12,1.11,0 | 290s,100s,0s |
| e,a | ,, | 60m +-.1 | 2.21,2.22,0 | 10s,200s,0s | | e,a | ,, | 60m +-.1 | 2.21,2.22,0 | 10s,200s,0s |
| e,d | ,, | 40m +-.1 | 4.01,1.11,0 | 190s,100s,0s | | e,d | ,, | 40m +-.1 | 4.01,1.11,0 | 190s,100s,0s |

View File

@ -9,9 +9,12 @@
#include "engine/hint.hpp" #include "engine/hint.hpp"
#include "util/coordinate_calculation.hpp" #include "util/coordinate_calculation.hpp"
#include <boost/algorithm/string/join.hpp>
#include <boost/assert.hpp> #include <boost/assert.hpp>
#include <boost/range/adaptor/transformed.hpp>
#include <boost/range/algorithm/transform.hpp> #include <boost/range/algorithm/transform.hpp>
#include <boost/range/adaptor/filtered.hpp>
#include <memory> #include <memory>
#include <vector> #include <vector>
@ -22,6 +25,8 @@ namespace engine
namespace api namespace api
{ {
static const constexpr char *INTERSECTION_DELIMITER = " / ";
class BaseAPI class BaseAPI
{ {
public: public:
@ -30,92 +35,129 @@ class BaseAPI
{ {
} }
util::json::Array MakeWaypoints(const std::vector<PhantomNodes> &segment_end_coordinates) const util::json::Array
MakeWaypoints(const std::vector<PhantomNodeCandidates> &waypoint_candidates) const
{ {
BOOST_ASSERT(parameters.coordinates.size() > 0); BOOST_ASSERT(parameters.coordinates.size() > 0);
BOOST_ASSERT(parameters.coordinates.size() == segment_end_coordinates.size() + 1); BOOST_ASSERT(parameters.coordinates.size() == waypoint_candidates.size());
util::json::Array waypoints; util::json::Array waypoints;
waypoints.values.resize(parameters.coordinates.size()); waypoints.values.resize(parameters.coordinates.size());
waypoints.values[0] = MakeWaypoint(segment_end_coordinates.front().source_phantom);
auto out_iter = std::next(waypoints.values.begin());
boost::range::transform( boost::range::transform(
segment_end_coordinates, out_iter, [this](const PhantomNodes &phantom_pair) { waypoint_candidates,
return MakeWaypoint(phantom_pair.target_phantom); waypoints.values.begin(),
}); [this](const PhantomNodeCandidates &candidates) { return MakeWaypoint(candidates); });
return waypoints; return waypoints;
} }
// FIXME: gcc 4.9 does not like MakeWaypoints to be protected // FIXME: gcc 4.9 does not like MakeWaypoints to be protected
// protected: // protected:
util::json::Object MakeWaypoint(const PhantomNode &phantom) const util::json::Object MakeWaypoint(const PhantomNodeCandidates &candidates) const
{
if (parameters.generate_hints)
{ {
// TODO: check forward/reverse // TODO: check forward/reverse
const auto toName = [this](const auto &phantom) {
return facade.GetNameForID(facade.GetNameIndex(phantom.forward_segment_id.id))
.to_string();
};
const auto noEmpty = [](const auto &name) { return !name.empty(); };
// At an intersection we may have multiple phantom node candidates.
// Combine them to represent the waypoint name.
std::string waypoint_name = boost::algorithm::join(
candidates | boost::adaptors::transformed(toName) | boost::adaptors::filtered(noEmpty),
INTERSECTION_DELIMITER);
const auto &snapped_location = candidatesSnappedLocation(candidates);
const auto &input_location = candidatesInputLocation(candidates);
if (parameters.generate_hints)
{
std::vector<SegmentHint> seg_hints(candidates.size());
std::transform(candidates.begin(),
candidates.end(),
seg_hints.begin(),
[this](const auto &phantom) {
return SegmentHint{phantom, facade.GetCheckSum()};
});
return json::makeWaypoint( return json::makeWaypoint(
phantom.location, snapped_location,
util::coordinate_calculation::greatCircleDistance(phantom.location, util::coordinate_calculation::greatCircleDistance(snapped_location, input_location),
phantom.input_location), waypoint_name,
facade.GetNameForID(facade.GetNameIndex(phantom.forward_segment_id.id)).to_string(), {std::move(seg_hints)});
Hint{phantom, facade.GetCheckSum()});
} }
else else
{ {
// TODO: check forward/reverse
return json::makeWaypoint( return json::makeWaypoint(
phantom.location, snapped_location,
util::coordinate_calculation::greatCircleDistance(phantom.location, util::coordinate_calculation::greatCircleDistance(snapped_location, input_location),
phantom.input_location), waypoint_name);
facade.GetNameForID(facade.GetNameIndex(phantom.forward_segment_id.id))
.to_string());
} }
} }
flatbuffers::Offset<flatbuffers::Vector<flatbuffers::Offset<fbresult::Waypoint>>> flatbuffers::Offset<flatbuffers::Vector<flatbuffers::Offset<fbresult::Waypoint>>>
MakeWaypoints(flatbuffers::FlatBufferBuilder *builder, MakeWaypoints(flatbuffers::FlatBufferBuilder *builder,
const std::vector<PhantomNodes> &segment_end_coordinates) const const std::vector<PhantomNodeCandidates> &waypoint_candidates) const
{ {
BOOST_ASSERT(parameters.coordinates.size() > 0); BOOST_ASSERT(parameters.coordinates.size() > 0);
BOOST_ASSERT(parameters.coordinates.size() == segment_end_coordinates.size() + 1); BOOST_ASSERT(parameters.coordinates.size() == waypoint_candidates.size());
std::vector<flatbuffers::Offset<fbresult::Waypoint>> waypoints; std::vector<flatbuffers::Offset<fbresult::Waypoint>> waypoints;
waypoints.resize(parameters.coordinates.size()); waypoints.resize(parameters.coordinates.size());
waypoints[0] =
MakeWaypoint(builder, segment_end_coordinates.front().source_phantom)->Finish();
std::transform(segment_end_coordinates.begin(), std::transform(waypoint_candidates.begin(),
segment_end_coordinates.end(), waypoint_candidates.end(),
std::next(waypoints.begin()), waypoints.begin(),
[this, builder](const PhantomNodes &phantom_pair) { [this, builder](const PhantomNodeCandidates &candidates) {
return MakeWaypoint(builder, phantom_pair.target_phantom)->Finish(); return MakeWaypoint(builder, candidates)->Finish();
}); });
return builder->CreateVector(waypoints); return builder->CreateVector(waypoints);
} }
// FIXME: gcc 4.9 does not like MakeWaypoints to be protected // FIXME: gcc 4.9 does not like MakeWaypoints to be protected
// protected: // protected:
std::unique_ptr<fbresult::WaypointBuilder> MakeWaypoint(flatbuffers::FlatBufferBuilder *builder, std::unique_ptr<fbresult::WaypointBuilder>
const PhantomNode &phantom) const MakeWaypoint(flatbuffers::FlatBufferBuilder *builder,
const PhantomNodeCandidates &candidates) const
{ {
const auto &snapped_location = candidatesSnappedLocation(candidates);
const auto &input_location = candidatesInputLocation(candidates);
auto location = auto location =
fbresult::Position(static_cast<double>(util::toFloating(phantom.location.lon)), fbresult::Position(static_cast<double>(util::toFloating(snapped_location.lon)),
static_cast<double>(util::toFloating(phantom.location.lat))); static_cast<double>(util::toFloating(snapped_location.lat)));
auto name_string = builder->CreateString(
facade.GetNameForID(facade.GetNameIndex(phantom.forward_segment_id.id)).to_string()); const auto toName = [this](const auto &phantom) {
return facade.GetNameForID(facade.GetNameIndex(phantom.forward_segment_id.id))
.to_string();
};
const auto noEmpty = [](const auto &name) { return !name.empty(); };
// At an intersection we may have multiple phantom node candidates.
// Combine them to represent the waypoint name.
std::string waypoint_name = boost::algorithm::join(
candidates | boost::adaptors::transformed(toName) | boost::adaptors::filtered(noEmpty),
INTERSECTION_DELIMITER);
auto name_string = builder->CreateString(waypoint_name);
flatbuffers::Offset<flatbuffers::String> hint_string; flatbuffers::Offset<flatbuffers::String> hint_string;
if (parameters.generate_hints) if (parameters.generate_hints)
{ {
hint_string = builder->CreateString(Hint{phantom, facade.GetCheckSum()}.ToBase64()); std::vector<SegmentHint> seg_hints(candidates.size());
std::transform(candidates.begin(),
candidates.end(),
seg_hints.begin(),
[this](const auto &phantom) {
return SegmentHint{phantom, facade.GetCheckSum()};
});
Hint hint{std::move(seg_hints)};
hint_string = builder->CreateString(hint.ToBase64());
} }
auto waypoint = std::make_unique<fbresult::WaypointBuilder>(*builder); auto waypoint = std::make_unique<fbresult::WaypointBuilder>(*builder);
waypoint->add_location(&location); waypoint->add_location(&location);
waypoint->add_distance(util::coordinate_calculation::greatCircleDistance( waypoint->add_distance(
phantom.location, phantom.input_location)); util::coordinate_calculation::greatCircleDistance(snapped_location, input_location));
waypoint->add_name(name_string); waypoint->add_name(name_string);
if (parameters.generate_hints) if (parameters.generate_hints)
{ {

View File

@ -51,14 +51,14 @@ namespace api
* Holds member attributes: * Holds member attributes:
* - coordinates: for specifying location(s) to services * - coordinates: for specifying location(s) to services
* - hints: hint for the service to derive the position(s) in the road network more efficiently, * - hints: hint for the service to derive the position(s) in the road network more efficiently,
* optional per coordinate * optional per coordinate. Multiple hints can be provided for a coordinate.
* - radiuses: limits the search for segments in the road network to given radius(es) in meter, * - radiuses: limits the search for segments in the road network to given radius(es) in meter,
* optional per coordinate * optional per coordinate
* - bearings: limits the search for segments in the road network to given bearing(s) in degree * - bearings: limits the search for segments in the road network to given bearing(s) in degree
* towards true north in clockwise direction, optional per coordinate * towards true north in clockwise direction, optional per coordinate
* - approaches: force the phantom node to start towards the node with the road country side. * - approaches: force the phantom node to start towards the node with the road country side.
* *
* \see OSRM, Coordinate, Hint, Bearing, RouteParame, RouteParameters, TableParameters, * \see OSRM, Coordinate, Hint, Bearing, RouteParameters, TableParameters,
* NearestParameters, TripParameters, MatchParameters and TileParameters * NearestParameters, TripParameters, MatchParameters and TileParameters
*/ */
struct BaseParameters struct BaseParameters

View File

@ -76,7 +76,7 @@ class MatchAPI final : public RouteAPI
routes.values.reserve(number_of_routes); routes.values.reserve(number_of_routes);
for (auto index : util::irange<std::size_t>(0UL, sub_matchings.size())) for (auto index : util::irange<std::size_t>(0UL, sub_matchings.size()))
{ {
auto route = MakeRoute(sub_routes[index].segment_end_coordinates, auto route = MakeRoute(sub_routes[index].leg_endpoints,
sub_routes[index].unpacked_path_segments, sub_routes[index].unpacked_path_segments,
sub_routes[index].source_traversed_in_reverse, sub_routes[index].source_traversed_in_reverse,
sub_routes[index].target_traversed_in_reverse); sub_routes[index].target_traversed_in_reverse);
@ -146,7 +146,7 @@ class MatchAPI final : public RouteAPI
} }
const auto &phantom = const auto &phantom =
sub_matchings[matching_index.sub_matching_index].nodes[matching_index.point_index]; sub_matchings[matching_index.sub_matching_index].nodes[matching_index.point_index];
auto waypoint = BaseAPI::MakeWaypoint(&fb_result, phantom); auto waypoint = BaseAPI::MakeWaypoint(&fb_result, {phantom});
waypoint->add_matchings_index(matching_index.sub_matching_index); waypoint->add_matchings_index(matching_index.sub_matching_index);
waypoint->add_alternatives_count(sub_matchings[matching_index.sub_matching_index] waypoint->add_alternatives_count(sub_matchings[matching_index.sub_matching_index]
.alternatives_count[matching_index.point_index]); .alternatives_count[matching_index.point_index]);
@ -200,7 +200,7 @@ class MatchAPI final : public RouteAPI
} }
const auto &phantom = const auto &phantom =
sub_matchings[matching_index.sub_matching_index].nodes[matching_index.point_index]; sub_matchings[matching_index.sub_matching_index].nodes[matching_index.point_index];
auto waypoint = BaseAPI::MakeWaypoint(phantom); auto waypoint = BaseAPI::MakeWaypoint({phantom});
waypoint.values["matchings_index"] = matching_index.sub_matching_index; waypoint.values["matchings_index"] = matching_index.sub_matching_index;
waypoint.values["waypoint_index"] = matching_index.point_index; waypoint.values["waypoint_index"] = matching_index.point_index;
waypoint.values["alternatives_count"] = waypoint.values["alternatives_count"] =

View File

@ -71,7 +71,7 @@ class NearestAPI final : public BaseAPI
auto node_values = MakeNodes(phantom_node); auto node_values = MakeNodes(phantom_node);
fbresult::Uint64Pair nodes{node_values.first, node_values.second}; fbresult::Uint64Pair nodes{node_values.first, node_values.second};
auto waypoint = MakeWaypoint(&fb_result, phantom_node); auto waypoint = MakeWaypoint(&fb_result, {phantom_node});
waypoint->add_nodes(&nodes); waypoint->add_nodes(&nodes);
return waypoint->Finish(); return waypoint->Finish();
}); });
@ -100,7 +100,7 @@ class NearestAPI final : public BaseAPI
waypoints.values.begin(), waypoints.values.begin(),
[this](const PhantomNodeWithDistance &phantom_with_distance) { [this](const PhantomNodeWithDistance &phantom_with_distance) {
auto &phantom_node = phantom_with_distance.phantom_node; auto &phantom_node = phantom_with_distance.phantom_node;
auto waypoint = MakeWaypoint(phantom_node); auto waypoint = MakeWaypoint({phantom_node});
util::json::Array nodes; util::json::Array nodes;

View File

@ -47,8 +47,8 @@ class RouteAPI : public BaseAPI
void void
MakeResponse(const InternalManyRoutesResult &raw_routes, MakeResponse(const InternalManyRoutesResult &raw_routes,
const std::vector<PhantomNodes> const std::vector<PhantomNodeCandidates>
&all_start_end_points, // all used coordinates, ignoring waypoints= parameter &waypoint_candidates, // all used coordinates, ignoring waypoints= parameter
osrm::engine::api::ResultT &response) const osrm::engine::api::ResultT &response) const
{ {
BOOST_ASSERT(!raw_routes.routes.empty()); BOOST_ASSERT(!raw_routes.routes.empty());
@ -56,19 +56,19 @@ class RouteAPI : public BaseAPI
if (response.is<flatbuffers::FlatBufferBuilder>()) if (response.is<flatbuffers::FlatBufferBuilder>())
{ {
auto &fb_result = response.get<flatbuffers::FlatBufferBuilder>(); auto &fb_result = response.get<flatbuffers::FlatBufferBuilder>();
MakeResponse(raw_routes, all_start_end_points, fb_result); MakeResponse(raw_routes, waypoint_candidates, fb_result);
} }
else else
{ {
auto &json_result = response.get<util::json::Object>(); auto &json_result = response.get<util::json::Object>();
MakeResponse(raw_routes, all_start_end_points, json_result); MakeResponse(raw_routes, waypoint_candidates, json_result);
} }
} }
void void
MakeResponse(const InternalManyRoutesResult &raw_routes, MakeResponse(const InternalManyRoutesResult &raw_routes,
const std::vector<PhantomNodes> const std::vector<PhantomNodeCandidates>
&all_start_end_points, // all used coordinates, ignoring waypoints= parameter &waypoint_candidates, // all used coordinates, ignoring waypoints= parameter
flatbuffers::FlatBufferBuilder &fb_result) const flatbuffers::FlatBufferBuilder &fb_result) const
{ {
@ -80,8 +80,8 @@ class RouteAPI : public BaseAPI
} }
auto response = auto response =
MakeFBResponse(raw_routes, fb_result, [this, &all_start_end_points, &fb_result]() { MakeFBResponse(raw_routes, fb_result, [this, &waypoint_candidates, &fb_result]() {
return BaseAPI::MakeWaypoints(&fb_result, all_start_end_points); return BaseAPI::MakeWaypoints(&fb_result, waypoint_candidates);
}); });
if (!data_timestamp.empty()) if (!data_timestamp.empty())
@ -93,8 +93,8 @@ class RouteAPI : public BaseAPI
void void
MakeResponse(const InternalManyRoutesResult &raw_routes, MakeResponse(const InternalManyRoutesResult &raw_routes,
const std::vector<PhantomNodes> const std::vector<PhantomNodeCandidates>
&all_start_end_points, // all used coordinates, ignoring waypoints= parameter &waypoint_candidates, // all used coordinates, ignoring waypoints= parameter
util::json::Object &response) const util::json::Object &response) const
{ {
util::json::Array jsRoutes; util::json::Array jsRoutes;
@ -104,7 +104,7 @@ class RouteAPI : public BaseAPI
if (!route.is_valid()) if (!route.is_valid())
continue; continue;
jsRoutes.values.push_back(MakeRoute(route.segment_end_coordinates, jsRoutes.values.push_back(MakeRoute(route.leg_endpoints,
route.unpacked_path_segments, route.unpacked_path_segments,
route.source_traversed_in_reverse, route.source_traversed_in_reverse,
route.target_traversed_in_reverse)); route.target_traversed_in_reverse));
@ -112,7 +112,7 @@ class RouteAPI : public BaseAPI
if (!parameters.skip_waypoints) if (!parameters.skip_waypoints)
{ {
response.values["waypoints"] = BaseAPI::MakeWaypoints(all_start_end_points); response.values["waypoints"] = BaseAPI::MakeWaypoints(waypoint_candidates);
} }
response.values["routes"] = std::move(jsRoutes); response.values["routes"] = std::move(jsRoutes);
response.values["code"] = "Ok"; response.values["code"] = "Ok";
@ -138,7 +138,7 @@ class RouteAPI : public BaseAPI
continue; continue;
routes.push_back(MakeRoute(fb_result, routes.push_back(MakeRoute(fb_result,
raw_route.segment_end_coordinates, raw_route.leg_endpoints,
raw_route.unpacked_path_segments, raw_route.unpacked_path_segments,
raw_route.source_traversed_in_reverse, raw_route.source_traversed_in_reverse,
raw_route.target_traversed_in_reverse)); raw_route.target_traversed_in_reverse));
@ -328,12 +328,12 @@ class RouteAPI : public BaseAPI
flatbuffers::Offset<fbresult::RouteObject> flatbuffers::Offset<fbresult::RouteObject>
MakeRoute(flatbuffers::FlatBufferBuilder &fb_result, MakeRoute(flatbuffers::FlatBufferBuilder &fb_result,
const std::vector<PhantomNodes> &segment_end_coordinates, const std::vector<PhantomEndpoints> &leg_endpoints,
const std::vector<std::vector<PathData>> &unpacked_path_segments, const std::vector<std::vector<PathData>> &unpacked_path_segments,
const std::vector<bool> &source_traversed_in_reverse, const std::vector<bool> &source_traversed_in_reverse,
const std::vector<bool> &target_traversed_in_reverse) const const std::vector<bool> &target_traversed_in_reverse) const
{ {
auto legs_info = MakeLegs(segment_end_coordinates, auto legs_info = MakeLegs(leg_endpoints,
unpacked_path_segments, unpacked_path_segments,
source_traversed_in_reverse, source_traversed_in_reverse,
target_traversed_in_reverse); target_traversed_in_reverse);
@ -705,12 +705,12 @@ class RouteAPI : public BaseAPI
return fb_result.CreateVector(intersections); return fb_result.CreateVector(intersections);
} }
util::json::Object MakeRoute(const std::vector<PhantomNodes> &segment_end_coordinates, util::json::Object MakeRoute(const std::vector<PhantomEndpoints> &leg_endpoints,
const std::vector<std::vector<PathData>> &unpacked_path_segments, const std::vector<std::vector<PathData>> &unpacked_path_segments,
const std::vector<bool> &source_traversed_in_reverse, const std::vector<bool> &source_traversed_in_reverse,
const std::vector<bool> &target_traversed_in_reverse) const const std::vector<bool> &target_traversed_in_reverse) const
{ {
auto legs_info = MakeLegs(segment_end_coordinates, auto legs_info = MakeLegs(leg_endpoints,
unpacked_path_segments, unpacked_path_segments,
source_traversed_in_reverse, source_traversed_in_reverse,
target_traversed_in_reverse); target_traversed_in_reverse);
@ -868,7 +868,7 @@ class RouteAPI : public BaseAPI
const RouteParameters &parameters; const RouteParameters &parameters;
std::pair<std::vector<guidance::RouteLeg>, std::vector<guidance::LegGeometry>> std::pair<std::vector<guidance::RouteLeg>, std::vector<guidance::LegGeometry>>
MakeLegs(const std::vector<PhantomNodes> &segment_end_coordinates, MakeLegs(const std::vector<PhantomEndpoints> &leg_endpoints,
const std::vector<std::vector<PathData>> &unpacked_path_segments, const std::vector<std::vector<PathData>> &unpacked_path_segments,
const std::vector<bool> &source_traversed_in_reverse, const std::vector<bool> &source_traversed_in_reverse,
const std::vector<bool> &target_traversed_in_reverse) const const std::vector<bool> &target_traversed_in_reverse) const
@ -877,13 +877,13 @@ class RouteAPI : public BaseAPI
std::make_pair(std::vector<guidance::RouteLeg>(), std::vector<guidance::LegGeometry>()); std::make_pair(std::vector<guidance::RouteLeg>(), std::vector<guidance::LegGeometry>());
auto &legs = result.first; auto &legs = result.first;
auto &leg_geometries = result.second; auto &leg_geometries = result.second;
auto number_of_legs = segment_end_coordinates.size(); auto number_of_legs = leg_endpoints.size();
legs.reserve(number_of_legs); legs.reserve(number_of_legs);
leg_geometries.reserve(number_of_legs); leg_geometries.reserve(number_of_legs);
for (auto idx : util::irange<std::size_t>(0UL, number_of_legs)) for (auto idx : util::irange<std::size_t>(0UL, number_of_legs))
{ {
const auto &phantoms = segment_end_coordinates[idx]; const auto &phantoms = leg_endpoints[idx];
const auto &path_data = unpacked_path_segments[idx]; const auto &path_data = unpacked_path_segments[idx];
const bool reversed_source = source_traversed_in_reverse[idx]; const bool reversed_source = source_traversed_in_reverse[idx];

View File

@ -48,25 +48,25 @@ class TableAPI final : public BaseAPI
virtual void virtual void
MakeResponse(const std::pair<std::vector<EdgeDuration>, std::vector<EdgeDistance>> &tables, MakeResponse(const std::pair<std::vector<EdgeDuration>, std::vector<EdgeDistance>> &tables,
const std::vector<PhantomNode> &phantoms, const std::vector<PhantomNodeCandidates> &candidates,
const std::vector<TableCellRef> &fallback_speed_cells, const std::vector<TableCellRef> &fallback_speed_cells,
osrm::engine::api::ResultT &response) const osrm::engine::api::ResultT &response) const
{ {
if (response.is<flatbuffers::FlatBufferBuilder>()) if (response.is<flatbuffers::FlatBufferBuilder>())
{ {
auto &fb_result = response.get<flatbuffers::FlatBufferBuilder>(); auto &fb_result = response.get<flatbuffers::FlatBufferBuilder>();
MakeResponse(tables, phantoms, fallback_speed_cells, fb_result); MakeResponse(tables, candidates, fallback_speed_cells, fb_result);
} }
else else
{ {
auto &json_result = response.get<util::json::Object>(); auto &json_result = response.get<util::json::Object>();
MakeResponse(tables, phantoms, fallback_speed_cells, json_result); MakeResponse(tables, candidates, fallback_speed_cells, json_result);
} }
} }
virtual void virtual void
MakeResponse(const std::pair<std::vector<EdgeDuration>, std::vector<EdgeDistance>> &tables, MakeResponse(const std::pair<std::vector<EdgeDuration>, std::vector<EdgeDistance>> &tables,
const std::vector<PhantomNode> &phantoms, const std::vector<PhantomNodeCandidates> &candidates,
const std::vector<TableCellRef> &fallback_speed_cells, const std::vector<TableCellRef> &fallback_speed_cells,
flatbuffers::FlatBufferBuilder &fb_result) const flatbuffers::FlatBufferBuilder &fb_result) const
{ {
@ -86,15 +86,15 @@ class TableAPI final : public BaseAPI
{ {
if (!parameters.skip_waypoints) if (!parameters.skip_waypoints)
{ {
sources = MakeWaypoints(fb_result, phantoms); sources = MakeWaypoints(fb_result, candidates);
} }
number_of_sources = phantoms.size(); number_of_sources = candidates.size();
} }
else else
{ {
if (!parameters.skip_waypoints) if (!parameters.skip_waypoints)
{ {
sources = MakeWaypoints(fb_result, phantoms, parameters.sources); sources = MakeWaypoints(fb_result, candidates, parameters.sources);
} }
} }
@ -104,15 +104,15 @@ class TableAPI final : public BaseAPI
{ {
if (!parameters.skip_waypoints) if (!parameters.skip_waypoints)
{ {
destinations = MakeWaypoints(fb_result, phantoms); destinations = MakeWaypoints(fb_result, candidates);
} }
number_of_destinations = phantoms.size(); number_of_destinations = candidates.size();
} }
else else
{ {
if (!parameters.skip_waypoints) if (!parameters.skip_waypoints)
{ {
destinations = MakeWaypoints(fb_result, phantoms, parameters.destinations); destinations = MakeWaypoints(fb_result, candidates, parameters.destinations);
} }
} }
@ -168,7 +168,7 @@ class TableAPI final : public BaseAPI
virtual void virtual void
MakeResponse(const std::pair<std::vector<EdgeDuration>, std::vector<EdgeDistance>> &tables, MakeResponse(const std::pair<std::vector<EdgeDuration>, std::vector<EdgeDistance>> &tables,
const std::vector<PhantomNode> &phantoms, const std::vector<PhantomNodeCandidates> &candidates,
const std::vector<TableCellRef> &fallback_speed_cells, const std::vector<TableCellRef> &fallback_speed_cells,
util::json::Object &response) const util::json::Object &response) const
{ {
@ -180,15 +180,15 @@ class TableAPI final : public BaseAPI
{ {
if (!parameters.skip_waypoints) if (!parameters.skip_waypoints)
{ {
response.values["sources"] = MakeWaypoints(phantoms); response.values["sources"] = MakeWaypoints(candidates);
} }
number_of_sources = phantoms.size(); number_of_sources = candidates.size();
} }
else else
{ {
if (!parameters.skip_waypoints) if (!parameters.skip_waypoints)
{ {
response.values["sources"] = MakeWaypoints(phantoms, parameters.sources); response.values["sources"] = MakeWaypoints(candidates, parameters.sources);
} }
} }
@ -196,15 +196,16 @@ class TableAPI final : public BaseAPI
{ {
if (!parameters.skip_waypoints) if (!parameters.skip_waypoints)
{ {
response.values["destinations"] = MakeWaypoints(phantoms); response.values["destinations"] = MakeWaypoints(candidates);
} }
number_of_destinations = phantoms.size(); number_of_destinations = candidates.size();
} }
else else
{ {
if (!parameters.skip_waypoints) if (!parameters.skip_waypoints)
{ {
response.values["destinations"] = MakeWaypoints(phantoms, parameters.destinations); response.values["destinations"] =
MakeWaypoints(candidates, parameters.destinations);
} }
} }
@ -236,31 +237,33 @@ class TableAPI final : public BaseAPI
protected: protected:
virtual flatbuffers::Offset<flatbuffers::Vector<flatbuffers::Offset<fbresult::Waypoint>>> virtual flatbuffers::Offset<flatbuffers::Vector<flatbuffers::Offset<fbresult::Waypoint>>>
MakeWaypoints(flatbuffers::FlatBufferBuilder &builder, MakeWaypoints(flatbuffers::FlatBufferBuilder &builder,
const std::vector<PhantomNode> &phantoms) const const std::vector<PhantomNodeCandidates> &candidates) const
{ {
std::vector<flatbuffers::Offset<fbresult::Waypoint>> waypoints; std::vector<flatbuffers::Offset<fbresult::Waypoint>> waypoints;
waypoints.reserve(phantoms.size()); waypoints.reserve(candidates.size());
BOOST_ASSERT(phantoms.size() == parameters.coordinates.size()); BOOST_ASSERT(candidates.size() == parameters.coordinates.size());
boost::range::transform( boost::range::transform(candidates,
phantoms, std::back_inserter(waypoints), [this, &builder](const PhantomNode &phantom) { std::back_inserter(waypoints),
return BaseAPI::MakeWaypoint(&builder, phantom)->Finish(); [this, &builder](const PhantomNodeCandidates &candidates) {
return BaseAPI::MakeWaypoint(&builder, candidates)->Finish();
}); });
return builder.CreateVector(waypoints); return builder.CreateVector(waypoints);
} }
virtual flatbuffers::Offset<flatbuffers::Vector<flatbuffers::Offset<fbresult::Waypoint>>> virtual flatbuffers::Offset<flatbuffers::Vector<flatbuffers::Offset<fbresult::Waypoint>>>
MakeWaypoints(flatbuffers::FlatBufferBuilder &builder, MakeWaypoints(flatbuffers::FlatBufferBuilder &builder,
const std::vector<PhantomNode> &phantoms, const std::vector<PhantomNodeCandidates> &candidates,
const std::vector<std::size_t> &indices) const const std::vector<std::size_t> &indices) const
{ {
std::vector<flatbuffers::Offset<fbresult::Waypoint>> waypoints; std::vector<flatbuffers::Offset<fbresult::Waypoint>> waypoints;
waypoints.reserve(indices.size()); waypoints.reserve(indices.size());
boost::range::transform(indices, boost::range::transform(
indices,
std::back_inserter(waypoints), std::back_inserter(waypoints),
[this, &builder, phantoms](const std::size_t idx) { [this, &builder, &candidates](const std::size_t idx) {
BOOST_ASSERT(idx < phantoms.size()); BOOST_ASSERT(idx < candidates.size());
return BaseAPI::MakeWaypoint(&builder, phantoms[idx])->Finish(); return BaseAPI::MakeWaypoint(&builder, candidates[idx])->Finish();
}); });
return builder.CreateVector(waypoints); return builder.CreateVector(waypoints);
} }
@ -313,29 +316,31 @@ class TableAPI final : public BaseAPI
return builder.CreateVector(fb_table); return builder.CreateVector(fb_table);
} }
virtual util::json::Array MakeWaypoints(const std::vector<PhantomNode> &phantoms) const virtual util::json::Array
MakeWaypoints(const std::vector<PhantomNodeCandidates> &candidates) const
{ {
util::json::Array json_waypoints; util::json::Array json_waypoints;
json_waypoints.values.reserve(phantoms.size()); json_waypoints.values.reserve(candidates.size());
BOOST_ASSERT(phantoms.size() == parameters.coordinates.size()); BOOST_ASSERT(candidates.size() == parameters.coordinates.size());
boost::range::transform( boost::range::transform(candidates,
phantoms,
std::back_inserter(json_waypoints.values), std::back_inserter(json_waypoints.values),
[this](const PhantomNode &phantom) { return BaseAPI::MakeWaypoint(phantom); }); [this](const PhantomNodeCandidates &candidates) {
return BaseAPI::MakeWaypoint(candidates);
});
return json_waypoints; return json_waypoints;
} }
virtual util::json::Array MakeWaypoints(const std::vector<PhantomNode> &phantoms, virtual util::json::Array MakeWaypoints(const std::vector<PhantomNodeCandidates> &candidates,
const std::vector<std::size_t> &indices) const const std::vector<std::size_t> &indices) const
{ {
util::json::Array json_waypoints; util::json::Array json_waypoints;
json_waypoints.values.reserve(indices.size()); json_waypoints.values.reserve(indices.size());
boost::range::transform(indices, boost::range::transform(indices,
std::back_inserter(json_waypoints.values), std::back_inserter(json_waypoints.values),
[this, phantoms](const std::size_t idx) { [this, &candidates](const std::size_t idx) {
BOOST_ASSERT(idx < phantoms.size()); BOOST_ASSERT(idx < candidates.size());
return BaseAPI::MakeWaypoint(phantoms[idx]); return BaseAPI::MakeWaypoint(candidates[idx]);
}); });
return json_waypoints; return json_waypoints;
} }

View File

@ -26,7 +26,7 @@ class TripAPI final : public RouteAPI
} }
void MakeResponse(const std::vector<std::vector<NodeID>> &sub_trips, void MakeResponse(const std::vector<std::vector<NodeID>> &sub_trips,
const std::vector<InternalRouteResult> &sub_routes, const std::vector<InternalRouteResult> &sub_routes,
const std::vector<PhantomNode> &phantoms, const std::vector<PhantomNodeCandidates> &candidates,
osrm::engine::api::ResultT &response) const osrm::engine::api::ResultT &response) const
{ {
BOOST_ASSERT(sub_trips.size() == sub_routes.size()); BOOST_ASSERT(sub_trips.size() == sub_routes.size());
@ -34,17 +34,17 @@ class TripAPI final : public RouteAPI
if (response.is<flatbuffers::FlatBufferBuilder>()) if (response.is<flatbuffers::FlatBufferBuilder>())
{ {
auto &fb_result = response.get<flatbuffers::FlatBufferBuilder>(); auto &fb_result = response.get<flatbuffers::FlatBufferBuilder>();
MakeResponse(sub_trips, sub_routes, phantoms, fb_result); MakeResponse(sub_trips, sub_routes, candidates, fb_result);
} }
else else
{ {
auto &json_result = response.get<util::json::Object>(); auto &json_result = response.get<util::json::Object>();
MakeResponse(sub_trips, sub_routes, phantoms, json_result); MakeResponse(sub_trips, sub_routes, candidates, json_result);
} }
} }
void MakeResponse(const std::vector<std::vector<NodeID>> &sub_trips, void MakeResponse(const std::vector<std::vector<NodeID>> &sub_trips,
const std::vector<InternalRouteResult> &sub_routes, const std::vector<InternalRouteResult> &sub_routes,
const std::vector<PhantomNode> &phantoms, const std::vector<PhantomNodeCandidates> &candidates,
flatbuffers::FlatBufferBuilder &fb_result) const flatbuffers::FlatBufferBuilder &fb_result) const
{ {
auto data_timestamp = facade.GetTimestamp(); auto data_timestamp = facade.GetTimestamp();
@ -55,8 +55,8 @@ class TripAPI final : public RouteAPI
} }
auto response = auto response =
MakeFBResponse(sub_routes, fb_result, [this, &fb_result, &sub_trips, &phantoms]() { MakeFBResponse(sub_routes, fb_result, [this, &fb_result, &sub_trips, &candidates]() {
return MakeWaypoints(fb_result, sub_trips, phantoms); return MakeWaypoints(fb_result, sub_trips, candidates);
}); });
if (!data_timestamp.empty()) if (!data_timestamp.empty())
@ -67,7 +67,7 @@ class TripAPI final : public RouteAPI
} }
void MakeResponse(const std::vector<std::vector<NodeID>> &sub_trips, void MakeResponse(const std::vector<std::vector<NodeID>> &sub_trips,
const std::vector<InternalRouteResult> &sub_routes, const std::vector<InternalRouteResult> &sub_routes,
const std::vector<PhantomNode> &phantoms, const std::vector<PhantomNodeCandidates> &candidates,
util::json::Object &response) const util::json::Object &response) const
{ {
auto number_of_routes = sub_trips.size(); auto number_of_routes = sub_trips.size();
@ -75,7 +75,7 @@ class TripAPI final : public RouteAPI
routes.values.reserve(number_of_routes); routes.values.reserve(number_of_routes);
for (auto index : util::irange<std::size_t>(0UL, sub_trips.size())) for (auto index : util::irange<std::size_t>(0UL, sub_trips.size()))
{ {
auto route = MakeRoute(sub_routes[index].segment_end_coordinates, auto route = MakeRoute(sub_routes[index].leg_endpoints,
sub_routes[index].unpacked_path_segments, sub_routes[index].unpacked_path_segments,
sub_routes[index].source_traversed_in_reverse, sub_routes[index].source_traversed_in_reverse,
sub_routes[index].target_traversed_in_reverse); sub_routes[index].target_traversed_in_reverse);
@ -83,7 +83,7 @@ class TripAPI final : public RouteAPI
} }
if (!parameters.skip_waypoints) if (!parameters.skip_waypoints)
{ {
response.values["waypoints"] = MakeWaypoints(sub_trips, phantoms); response.values["waypoints"] = MakeWaypoints(sub_trips, candidates);
} }
response.values["trips"] = std::move(routes); response.values["trips"] = std::move(routes);
response.values["code"] = "Ok"; response.values["code"] = "Ok";
@ -120,7 +120,7 @@ class TripAPI final : public RouteAPI
flatbuffers::Offset<flatbuffers::Vector<flatbuffers::Offset<fbresult::Waypoint>>> flatbuffers::Offset<flatbuffers::Vector<flatbuffers::Offset<fbresult::Waypoint>>>
MakeWaypoints(flatbuffers::FlatBufferBuilder &fb_result, MakeWaypoints(flatbuffers::FlatBufferBuilder &fb_result,
const std::vector<std::vector<NodeID>> &sub_trips, const std::vector<std::vector<NodeID>> &sub_trips,
const std::vector<PhantomNode> &phantoms) const const std::vector<PhantomNodeCandidates> &candidates) const
{ {
std::vector<flatbuffers::Offset<fbresult::Waypoint>> waypoints; std::vector<flatbuffers::Offset<fbresult::Waypoint>> waypoints;
waypoints.reserve(parameters.coordinates.size()); waypoints.reserve(parameters.coordinates.size());
@ -132,7 +132,7 @@ class TripAPI final : public RouteAPI
auto trip_index = input_idx_to_trip_idx[input_index]; auto trip_index = input_idx_to_trip_idx[input_index];
BOOST_ASSERT(!trip_index.NotUsed()); BOOST_ASSERT(!trip_index.NotUsed());
auto waypoint = BaseAPI::MakeWaypoint(&fb_result, phantoms[input_index]); auto waypoint = BaseAPI::MakeWaypoint(&fb_result, candidates[input_index]);
waypoint->add_waypoint_index(trip_index.point_index); waypoint->add_waypoint_index(trip_index.point_index);
waypoint->add_trips_index(trip_index.sub_trip_index); waypoint->add_trips_index(trip_index.sub_trip_index);
waypoints.push_back(waypoint->Finish()); waypoints.push_back(waypoint->Finish());
@ -142,7 +142,7 @@ class TripAPI final : public RouteAPI
} }
util::json::Array MakeWaypoints(const std::vector<std::vector<NodeID>> &sub_trips, util::json::Array MakeWaypoints(const std::vector<std::vector<NodeID>> &sub_trips,
const std::vector<PhantomNode> &phantoms) const const std::vector<PhantomNodeCandidates> &candidates) const
{ {
util::json::Array waypoints; util::json::Array waypoints;
waypoints.values.reserve(parameters.coordinates.size()); waypoints.values.reserve(parameters.coordinates.size());
@ -154,7 +154,7 @@ class TripAPI final : public RouteAPI
auto trip_index = input_idx_to_trip_idx[input_index]; auto trip_index = input_idx_to_trip_idx[input_index];
BOOST_ASSERT(!trip_index.NotUsed()); BOOST_ASSERT(!trip_index.NotUsed());
auto waypoint = BaseAPI::MakeWaypoint(phantoms[input_index]); auto waypoint = BaseAPI::MakeWaypoint(candidates[input_index]);
waypoint.values["trips_index"] = trip_index.sub_trip_index; waypoint.values["trips_index"] = trip_index.sub_trip_index;
waypoint.values["waypoint_index"] = trip_index.point_index; waypoint.values["waypoint_index"] = trip_index.point_index;
waypoints.values.push_back(std::move(waypoint)); waypoints.values.push_back(std::move(waypoint));

View File

@ -323,127 +323,41 @@ class ContiguousInternalMemoryDataFacadeBase : public BaseDataFacade
std::vector<PhantomNodeWithDistance> std::vector<PhantomNodeWithDistance>
NearestPhantomNodesInRange(const util::Coordinate input_coordinate, NearestPhantomNodesInRange(const util::Coordinate input_coordinate,
const float max_distance,
const Approach approach,
const bool use_all_edges) const override final
{
BOOST_ASSERT(m_geospatial_query.get());
return m_geospatial_query->NearestPhantomNodesInRange(
input_coordinate, max_distance, approach, use_all_edges);
}
std::vector<PhantomNodeWithDistance>
NearestPhantomNodesInRange(const util::Coordinate input_coordinate,
const float max_distance,
const int bearing,
const int bearing_range,
const Approach approach,
const bool use_all_edges) const override final
{
BOOST_ASSERT(m_geospatial_query.get());
return m_geospatial_query->NearestPhantomNodesInRange(
input_coordinate, max_distance, bearing, bearing_range, approach, use_all_edges);
}
std::vector<PhantomNodeWithDistance>
NearestPhantomNodes(const util::Coordinate input_coordinate,
const unsigned max_results,
const Approach approach) const override final
{
BOOST_ASSERT(m_geospatial_query.get());
return m_geospatial_query->NearestPhantomNodes(input_coordinate, max_results, approach);
}
std::vector<PhantomNodeWithDistance>
NearestPhantomNodes(const util::Coordinate input_coordinate,
const unsigned max_results,
const double max_distance, const double max_distance,
const boost::optional<Bearing> bearing,
const Approach approach,
const bool use_all_edges) const override final
{
BOOST_ASSERT(m_geospatial_query.get());
return m_geospatial_query->NearestPhantomNodes(
input_coordinate, approach, boost::none, max_distance, bearing, use_all_edges);
}
std::vector<PhantomNodeWithDistance>
NearestPhantomNodes(const util::Coordinate input_coordinate,
const size_t max_results,
const boost::optional<double> max_distance,
const boost::optional<Bearing> bearing,
const Approach approach) const override final const Approach approach) const override final
{ {
BOOST_ASSERT(m_geospatial_query.get()); BOOST_ASSERT(m_geospatial_query.get());
return m_geospatial_query->NearestPhantomNodes( return m_geospatial_query->NearestPhantomNodes(
input_coordinate, max_results, max_distance, approach); input_coordinate, approach, max_results, max_distance, bearing, boost::none);
} }
std::vector<PhantomNodeWithDistance> PhantomCandidateAlternatives
NearestPhantomNodes(const util::Coordinate input_coordinate, NearestCandidatesWithAlternativeFromBigComponent(const util::Coordinate input_coordinate,
const unsigned max_results, const boost::optional<double> max_distance,
const int bearing, const boost::optional<Bearing> bearing,
const int bearing_range,
const Approach approach) const override final
{
BOOST_ASSERT(m_geospatial_query.get());
return m_geospatial_query->NearestPhantomNodes(
input_coordinate, max_results, bearing, bearing_range, approach);
}
std::vector<PhantomNodeWithDistance>
NearestPhantomNodes(const util::Coordinate input_coordinate,
const unsigned max_results,
const double max_distance,
const int bearing,
const int bearing_range,
const Approach approach) const override final
{
BOOST_ASSERT(m_geospatial_query.get());
return m_geospatial_query->NearestPhantomNodes(
input_coordinate, max_results, max_distance, bearing, bearing_range, approach);
}
std::pair<PhantomNode, PhantomNode>
NearestPhantomNodeWithAlternativeFromBigComponent(const util::Coordinate input_coordinate,
const Approach approach, const Approach approach,
const bool use_all_edges) const override final const bool use_all_edges) const override final
{ {
BOOST_ASSERT(m_geospatial_query.get()); BOOST_ASSERT(m_geospatial_query.get());
return m_geospatial_query->NearestPhantomNodeWithAlternativeFromBigComponent( return m_geospatial_query->NearestCandidatesWithAlternativeFromBigComponent(
input_coordinate, approach, use_all_edges); input_coordinate, approach, max_distance, bearing, use_all_edges);
}
std::pair<PhantomNode, PhantomNode>
NearestPhantomNodeWithAlternativeFromBigComponent(const util::Coordinate input_coordinate,
const double max_distance,
const Approach approach,
const bool use_all_edges) const override final
{
BOOST_ASSERT(m_geospatial_query.get());
return m_geospatial_query->NearestPhantomNodeWithAlternativeFromBigComponent(
input_coordinate, max_distance, approach, use_all_edges);
}
std::pair<PhantomNode, PhantomNode>
NearestPhantomNodeWithAlternativeFromBigComponent(const util::Coordinate input_coordinate,
const double max_distance,
const int bearing,
const int bearing_range,
const Approach approach,
const bool use_all_edges) const override final
{
BOOST_ASSERT(m_geospatial_query.get());
return m_geospatial_query->NearestPhantomNodeWithAlternativeFromBigComponent(
input_coordinate, max_distance, bearing, bearing_range, approach, use_all_edges);
}
std::pair<PhantomNode, PhantomNode>
NearestPhantomNodeWithAlternativeFromBigComponent(const util::Coordinate input_coordinate,
const int bearing,
const int bearing_range,
const Approach approach,
const bool use_all_edges) const override final
{
BOOST_ASSERT(m_geospatial_query.get());
return m_geospatial_query->NearestPhantomNodeWithAlternativeFromBigComponent(
input_coordinate, bearing, bearing_range, approach, use_all_edges);
} }
std::uint32_t GetCheckSum() const override final { return m_check_sum; } std::uint32_t GetCheckSum() const override final { return m_check_sum; }

View File

@ -35,6 +35,7 @@
#include <boost/range/any_range.hpp> #include <boost/range/any_range.hpp>
#include <cstddef> #include <cstddef>
#include <engine/bearing.hpp>
#include <string> #include <string>
#include <utility> #include <utility>
#include <vector> #include <vector>
@ -130,62 +131,24 @@ class BaseDataFacade
virtual std::vector<PhantomNodeWithDistance> virtual std::vector<PhantomNodeWithDistance>
NearestPhantomNodesInRange(const util::Coordinate input_coordinate, NearestPhantomNodesInRange(const util::Coordinate input_coordinate,
const float max_distance, const double max_distance,
const int bearing, const boost::optional<Bearing> bearing,
const int bearing_range,
const Approach approach,
const bool use_all_edges) const = 0;
virtual std::vector<PhantomNodeWithDistance>
NearestPhantomNodesInRange(const util::Coordinate input_coordinate,
const float max_distance,
const Approach approach, const Approach approach,
const bool use_all_edges) const = 0; const bool use_all_edges) const = 0;
virtual std::vector<PhantomNodeWithDistance> virtual std::vector<PhantomNodeWithDistance>
NearestPhantomNodes(const util::Coordinate input_coordinate, NearestPhantomNodes(const util::Coordinate input_coordinate,
const unsigned max_results, const size_t max_results,
const double max_distance, const boost::optional<double> max_distance,
const int bearing, const boost::optional<Bearing> bearing,
const int bearing_range,
const Approach approach) const = 0;
virtual std::vector<PhantomNodeWithDistance>
NearestPhantomNodes(const util::Coordinate input_coordinate,
const unsigned max_results,
const int bearing,
const int bearing_range,
const Approach approach) const = 0;
virtual std::vector<PhantomNodeWithDistance>
NearestPhantomNodes(const util::Coordinate input_coordinate,
const unsigned max_results,
const Approach approach) const = 0;
virtual std::vector<PhantomNodeWithDistance>
NearestPhantomNodes(const util::Coordinate input_coordinate,
const unsigned max_results,
const double max_distance,
const Approach approach) const = 0; const Approach approach) const = 0;
virtual std::pair<PhantomNode, PhantomNode> virtual PhantomCandidateAlternatives
NearestPhantomNodeWithAlternativeFromBigComponent(const util::Coordinate input_coordinate, NearestCandidatesWithAlternativeFromBigComponent(const util::Coordinate input_coordinate,
const boost::optional<double> max_distance,
const boost::optional<Bearing> bearing,
const Approach approach, const Approach approach,
const bool use_all_edges) const = 0; const bool use_all_edges) const = 0;
virtual std::pair<PhantomNode, PhantomNode>
NearestPhantomNodeWithAlternativeFromBigComponent(const util::Coordinate input_coordinate,
const double max_distance,
const Approach approach,
const bool use_all_edges) const = 0;
virtual std::pair<PhantomNode, PhantomNode>
NearestPhantomNodeWithAlternativeFromBigComponent(const util::Coordinate input_coordinate,
const double max_distance,
const int bearing,
const int bearing_range,
const Approach approach,
const bool use_all_edges) const = 0;
virtual std::pair<PhantomNode, PhantomNode>
NearestPhantomNodeWithAlternativeFromBigComponent(const util::Coordinate input_coordinate,
const int bearing,
const int bearing_range,
const Approach approach,
const bool use_all_edges = false) const = 0;
virtual bool HasLaneData(const EdgeID edge_based_edge_id) const = 0; virtual bool HasLaneData(const EdgeID edge_based_edge_id) const = 0;
virtual util::guidance::LaneTupleIdPair GetLaneData(const EdgeID edge_based_edge_id) const = 0; virtual util::guidance::LaneTupleIdPair GetLaneData(const EdgeID edge_based_edge_id) const = 0;

View File

@ -2,6 +2,7 @@
#define GEOSPATIAL_QUERY_HPP #define GEOSPATIAL_QUERY_HPP
#include "engine/approach.hpp" #include "engine/approach.hpp"
#include "engine/bearing.hpp"
#include "engine/phantom_node.hpp" #include "engine/phantom_node.hpp"
#include "util/bearing.hpp" #include "util/bearing.hpp"
#include "util/coordinate_calculation.hpp" #include "util/coordinate_calculation.hpp"
@ -22,10 +23,10 @@ namespace osrm
namespace engine namespace engine
{ {
inline std::pair<bool, bool> boolPairAnd(const std::pair<bool, bool> &A, inline std::pair<bool, bool> operator&&(const std::pair<bool, bool> &a,
const std::pair<bool, bool> &B) const std::pair<bool, bool> &b)
{ {
return std::make_pair(A.first && B.first, A.second && B.second); return {a.first && b.first, a.second && b.second};
} }
// Implements complex queries on top of an RTree and builds PhantomNodes from it. // Implements complex queries on top of an RTree and builds PhantomNodes from it.
@ -48,390 +49,241 @@ template <typename RTreeT, typename DataFacadeT> class GeospatialQuery
return rtree.SearchInBox(bbox); return rtree.SearchInBox(bbox);
} }
// Returns nearest PhantomNodes in the given bearing range within max_distance. // Returns max_results nearest PhantomNodes that are valid within the provided parameters.
// Does not filter by small/big component! // Does not filter by small/big component!
std::vector<PhantomNodeWithDistance> std::vector<PhantomNodeWithDistance>
NearestPhantomNodesInRange(const util::Coordinate input_coordinate, NearestPhantomNodes(const util::Coordinate input_coordinate,
const double max_distance,
const Approach approach, const Approach approach,
const bool use_all_edges) const const boost::optional<size_t> max_results,
const boost::optional<double> max_distance,
const boost::optional<Bearing> bearing_with_range,
const boost::optional<bool> use_all_edges) const
{ {
auto results = rtree.Nearest( auto results = rtree.Nearest(
input_coordinate, input_coordinate,
[this, approach, &input_coordinate, use_all_edges](const CandidateSegment &segment) { [this, approach, &input_coordinate, &bearing_with_range, &use_all_edges](
return boolPairAnd(
boolPairAnd(HasValidEdge(segment, use_all_edges), CheckSegmentExclude(segment)),
CheckApproach(input_coordinate, segment, approach));
},
[this, max_distance, input_coordinate](const std::size_t,
const CandidateSegment &segment) { const CandidateSegment &segment) {
return CheckSegmentDistance(input_coordinate, segment, max_distance); auto valid = CheckSegmentExclude(segment) &&
CheckApproach(input_coordinate, segment, approach) &&
(use_all_edges ? HasValidEdge(segment, *use_all_edges)
: HasValidEdge(segment)) &&
(bearing_with_range ? CheckSegmentBearing(segment, *bearing_with_range)
: std::make_pair(true, true));
return valid;
},
[this, &max_distance, &max_results, input_coordinate](const std::size_t num_results,
const CandidateSegment &segment) {
return (max_results && num_results >= *max_results) ||
(max_distance &&
CheckSegmentDistance(input_coordinate, segment, *max_distance));
}); });
return MakePhantomNodes(input_coordinate, results); return MakePhantomNodes(input_coordinate, results);
} }
// Returns nearest PhantomNodes in the given bearing range within max_distance. // Returns a list of phantom node candidates from the nearest location that are valid
// Does not filter by small/big component! // within the provided parameters. If there is tie between equidistant locations,
std::vector<PhantomNodeWithDistance> // we only pick candidates from one location.
NearestPhantomNodesInRange(const util::Coordinate input_coordinate, // If candidates do not include a node from a big component, an alternative list of candidates
const double max_distance, // from the nearest location which has nodes from a big component is returned.
const int bearing, PhantomCandidateAlternatives NearestCandidatesWithAlternativeFromBigComponent(
const int bearing_range, const util::Coordinate input_coordinate,
const Approach approach, const Approach approach,
const bool use_all_edges) const const boost::optional<double> max_distance,
const boost::optional<Bearing> bearing_with_range,
const boost::optional<bool> use_all_edges) const
{ {
auto results = rtree.Nearest( bool has_nearest = false;
input_coordinate,
[this, approach, &input_coordinate, bearing, bearing_range, use_all_edges](
const CandidateSegment &segment) {
auto use_direction =
boolPairAnd(CheckSegmentBearing(segment, bearing, bearing_range),
boolPairAnd(HasValidEdge(segment, use_all_edges),
CheckSegmentExclude(segment)));
use_direction =
boolPairAnd(use_direction, CheckApproach(input_coordinate, segment, approach));
return use_direction;
},
[this, max_distance, input_coordinate](const std::size_t,
const CandidateSegment &segment) {
return CheckSegmentDistance(input_coordinate, segment, max_distance);
});
return MakePhantomNodes(input_coordinate, results);
}
// Returns max_results nearest PhantomNodes in the given bearing range.
// Does not filter by small/big component!
std::vector<PhantomNodeWithDistance>
NearestPhantomNodes(const util::Coordinate input_coordinate,
const unsigned max_results,
const int bearing,
const int bearing_range,
const Approach approach) const
{
auto results = rtree.Nearest(
input_coordinate,
[this, approach, &input_coordinate, bearing, bearing_range](
const CandidateSegment &segment) {
auto use_direction =
boolPairAnd(CheckSegmentBearing(segment, bearing, bearing_range),
boolPairAnd(HasValidEdge(segment), CheckSegmentExclude(segment)));
return boolPairAnd(use_direction,
CheckApproach(input_coordinate, segment, approach));
},
[max_results](const std::size_t num_results, const CandidateSegment &) {
return num_results >= max_results;
});
return MakePhantomNodes(input_coordinate, results);
}
// Returns max_results nearest PhantomNodes in the given bearing range within the maximum
// distance.
// Does not filter by small/big component!
std::vector<PhantomNodeWithDistance>
NearestPhantomNodes(const util::Coordinate input_coordinate,
const unsigned max_results,
const double max_distance,
const int bearing,
const int bearing_range,
const Approach approach) const
{
auto results = rtree.Nearest(
input_coordinate,
[this, approach, &input_coordinate, bearing, bearing_range](
const CandidateSegment &segment) {
auto use_direction =
boolPairAnd(CheckSegmentBearing(segment, bearing, bearing_range),
boolPairAnd(HasValidEdge(segment), CheckSegmentExclude(segment)));
return boolPairAnd(use_direction,
CheckApproach(input_coordinate, segment, approach));
},
[this, max_distance, max_results, input_coordinate](const std::size_t num_results,
const CandidateSegment &segment) {
return num_results >= max_results ||
CheckSegmentDistance(input_coordinate, segment, max_distance);
});
return MakePhantomNodes(input_coordinate, results);
}
// Returns max_results nearest PhantomNodes.
// Does not filter by small/big component!
std::vector<PhantomNodeWithDistance>
NearestPhantomNodes(const util::Coordinate input_coordinate,
const unsigned max_results,
const Approach approach) const
{
auto results = rtree.Nearest(
input_coordinate,
[this, approach, &input_coordinate](const CandidateSegment &segment) {
return boolPairAnd(boolPairAnd(HasValidEdge(segment), CheckSegmentExclude(segment)),
CheckApproach(input_coordinate, segment, approach));
},
[max_results](const std::size_t num_results, const CandidateSegment &) {
return num_results >= max_results;
});
return MakePhantomNodes(input_coordinate, results);
}
// Returns max_results nearest PhantomNodes in the given max distance.
// Does not filter by small/big component!
std::vector<PhantomNodeWithDistance>
NearestPhantomNodes(const util::Coordinate input_coordinate,
const unsigned max_results,
const double max_distance,
const Approach approach) const
{
auto results = rtree.Nearest(
input_coordinate,
[this, approach, &input_coordinate](const CandidateSegment &segment) {
return boolPairAnd(boolPairAnd(HasValidEdge(segment), CheckSegmentExclude(segment)),
CheckApproach(input_coordinate, segment, approach));
},
[this, max_distance, max_results, input_coordinate](const std::size_t num_results,
const CandidateSegment &segment) {
return num_results >= max_results ||
CheckSegmentDistance(input_coordinate, segment, max_distance);
});
return MakePhantomNodes(input_coordinate, results);
}
// Returns the nearest phantom node. If this phantom node is not from a big component
// a second phantom node is return that is the nearest coordinate in a big component.
std::pair<PhantomNode, PhantomNode>
NearestPhantomNodeWithAlternativeFromBigComponent(const util::Coordinate input_coordinate,
const double max_distance,
const Approach approach,
const bool use_all_edges) const
{
bool has_small_component = false;
bool has_big_component = false; bool has_big_component = false;
Coordinate big_component_coord;
double big_component_distance = std::numeric_limits<double>::max();
Coordinate nearest_coord;
auto results = rtree.Nearest( auto results = rtree.Nearest(
input_coordinate, input_coordinate,
[this, [this,
approach, approach,
&input_coordinate, &input_coordinate,
&has_nearest,
&has_big_component, &has_big_component,
&has_small_component, &nearest_coord,
&use_all_edges](const CandidateSegment &segment) { &big_component_coord,
auto use_segment = &big_component_distance,
(!has_small_component || (!has_big_component && !IsTinyComponent(segment))); &use_all_edges,
auto use_directions = std::make_pair(use_segment, use_segment); &bearing_with_range](const CandidateSegment &segment) {
const auto valid_edges = HasValidEdge(segment, use_all_edges); auto is_big_component = !IsTinyComponent(segment);
const auto admissible_segments = CheckSegmentExclude(segment); auto not_nearest =
use_directions = boolPairAnd(use_directions, admissible_segments); has_nearest && segment.fixed_projected_coordinate != nearest_coord;
use_directions = boolPairAnd(use_directions, valid_edges); auto not_big =
use_directions = has_big_component && segment.fixed_projected_coordinate != big_component_coord;
boolPairAnd(use_directions, CheckApproach(input_coordinate, segment, approach));
if (use_directions.first || use_directions.second) /**
*
* Two reasons why we don't want this candidate:
* 1. A non-big component candidate that is not at the nearest location
* 2. A big component candidate that is not at the big location.
*
* It's possible that 1. could end up having the same location as the nearest big
* component node if we have yet to see one. However, we don't know this and it
* could lead to buffering large numbers of candidates before finding the big
* component location.
* By filtering out 1. nodes, this does mean that the alternative list of
* candidates will not have non-big component candidates. Given the alternative
* list of big component candidates is meant as a backup choice, this seems
* reasonable.
*/
if ((!is_big_component && not_nearest) || (is_big_component && not_big))
{ {
has_big_component = has_big_component || !IsTinyComponent(segment); return std::make_pair(false, false);
has_small_component = has_small_component || IsTinyComponent(segment); }
auto use_candidate =
CheckSegmentExclude(segment) &&
CheckApproach(input_coordinate, segment, approach) &&
(use_all_edges ? HasValidEdge(segment, *use_all_edges)
: HasValidEdge(segment)) &&
(bearing_with_range ? CheckSegmentBearing(segment, *bearing_with_range)
: std::make_pair(true, true));
if (use_candidate.first || use_candidate.second)
{
if (!has_nearest)
{
has_nearest = true;
nearest_coord = segment.fixed_projected_coordinate;
}
if (is_big_component && !has_big_component)
{
has_big_component = true;
big_component_coord = segment.fixed_projected_coordinate;
big_component_distance = GetSegmentDistance(input_coordinate, segment);
}
} }
return use_directions; return use_candidate;
}, },
[this, &has_big_component, max_distance, input_coordinate]( [this, &has_big_component, &max_distance, input_coordinate, &big_component_distance](
const std::size_t num_results, const CandidateSegment &segment) { const std::size_t /*num_results*/, const CandidateSegment &segment) {
return (num_results > 0 && has_big_component) || auto distance = GetSegmentDistance(input_coordinate, segment);
CheckSegmentDistance(input_coordinate, segment, max_distance); auto further_than_big_component = distance > big_component_distance;
auto no_more_candidates = has_big_component && further_than_big_component;
auto too_far_away = max_distance && distance > *max_distance;
// Time to terminate the search when:
// 1. We've found a node from a big component and the next candidate is further away
// than that node.
// 2. We're further away from the input then our max allowed distance.
return no_more_candidates || too_far_away;
}); });
if (results.size() == 0) return MakeAlternativeBigCandidates(input_coordinate, nearest_coord, results);
{
return std::make_pair(PhantomNode{}, PhantomNode{});
}
BOOST_ASSERT(results.size() == 1 || results.size() == 2);
return std::make_pair(MakePhantomNode(input_coordinate, results.front()).phantom_node,
MakePhantomNode(input_coordinate, results.back()).phantom_node);
}
// Returns the nearest phantom node. If this phantom node is not from a big component
// a second phantom node is return that is the nearest coordinate in a big component.
std::pair<PhantomNode, PhantomNode>
NearestPhantomNodeWithAlternativeFromBigComponent(const util::Coordinate input_coordinate,
const Approach approach,
const bool use_all_edges) const
{
bool has_small_component = false;
bool has_big_component = false;
auto results = rtree.Nearest(
input_coordinate,
[this,
approach,
&input_coordinate,
&has_big_component,
&has_small_component,
&use_all_edges](const CandidateSegment &segment) {
auto use_segment =
(!has_small_component || (!has_big_component && !IsTinyComponent(segment)));
auto use_directions = std::make_pair(use_segment, use_segment);
const auto valid_edges = HasValidEdge(segment, use_all_edges);
const auto admissible_segments = CheckSegmentExclude(segment);
use_directions = boolPairAnd(use_directions, admissible_segments);
use_directions = boolPairAnd(use_directions, valid_edges);
use_directions =
boolPairAnd(use_directions, CheckApproach(input_coordinate, segment, approach));
if (use_directions.first || use_directions.second)
{
has_big_component = has_big_component || !IsTinyComponent(segment);
has_small_component = has_small_component || IsTinyComponent(segment);
}
return use_directions;
},
[&has_big_component](const std::size_t num_results, const CandidateSegment &) {
return num_results > 0 && has_big_component;
});
if (results.size() == 0)
{
return std::make_pair(PhantomNode{}, PhantomNode{});
}
BOOST_ASSERT(results.size() == 1 || results.size() == 2);
return std::make_pair(MakePhantomNode(input_coordinate, results.front()).phantom_node,
MakePhantomNode(input_coordinate, results.back()).phantom_node);
}
// Returns the nearest phantom node. If this phantom node is not from a big component
// a second phantom node is return that is the nearest coordinate in a big component.
std::pair<PhantomNode, PhantomNode>
NearestPhantomNodeWithAlternativeFromBigComponent(const util::Coordinate input_coordinate,
const int bearing,
const int bearing_range,
const Approach approach,
const bool use_all_edges) const
{
bool has_small_component = false;
bool has_big_component = false;
auto results = rtree.Nearest(
input_coordinate,
[this,
approach,
&input_coordinate,
bearing,
bearing_range,
&has_big_component,
&has_small_component,
&use_all_edges](const CandidateSegment &segment) {
auto use_segment =
(!has_small_component || (!has_big_component && !IsTinyComponent(segment)));
auto use_directions = std::make_pair(use_segment, use_segment);
const auto admissible_segments = CheckSegmentExclude(segment);
if (use_segment)
{
use_directions =
boolPairAnd(CheckSegmentBearing(segment, bearing, bearing_range),
HasValidEdge(segment, use_all_edges));
use_directions = boolPairAnd(use_directions, admissible_segments);
use_directions = boolPairAnd(
use_directions, CheckApproach(input_coordinate, segment, approach));
if (use_directions.first || use_directions.second)
{
has_big_component = has_big_component || !IsTinyComponent(segment);
has_small_component = has_small_component || IsTinyComponent(segment);
}
}
return use_directions;
},
[&has_big_component](const std::size_t num_results, const CandidateSegment &) {
return num_results > 0 && has_big_component;
});
if (results.size() == 0)
{
return std::make_pair(PhantomNode{}, PhantomNode{});
}
BOOST_ASSERT(results.size() > 0);
return std::make_pair(MakePhantomNode(input_coordinate, results.front()).phantom_node,
MakePhantomNode(input_coordinate, results.back()).phantom_node);
}
// Returns the nearest phantom node. If this phantom node is not from a big component
// a second phantom node is return that is the nearest coordinate in a big component.
std::pair<PhantomNode, PhantomNode>
NearestPhantomNodeWithAlternativeFromBigComponent(const util::Coordinate input_coordinate,
const double max_distance,
const int bearing,
const int bearing_range,
const Approach approach,
const bool use_all_edges) const
{
bool has_small_component = false;
bool has_big_component = false;
auto results = rtree.Nearest(
input_coordinate,
[this,
approach,
&input_coordinate,
bearing,
bearing_range,
&has_big_component,
&has_small_component,
&use_all_edges](const CandidateSegment &segment) {
auto use_segment =
(!has_small_component || (!has_big_component && !IsTinyComponent(segment)));
auto use_directions = std::make_pair(use_segment, use_segment);
const auto admissible_segments = CheckSegmentExclude(segment);
if (use_segment)
{
use_directions =
boolPairAnd(CheckSegmentBearing(segment, bearing, bearing_range),
HasValidEdge(segment, use_all_edges));
use_directions = boolPairAnd(use_directions, admissible_segments);
use_directions = boolPairAnd(
use_directions, CheckApproach(input_coordinate, segment, approach));
if (use_directions.first || use_directions.second)
{
has_big_component = has_big_component || !IsTinyComponent(segment);
has_small_component = has_small_component || IsTinyComponent(segment);
}
}
return use_directions;
},
[this, &has_big_component, max_distance, input_coordinate](
const std::size_t num_results, const CandidateSegment &segment) {
return (num_results > 0 && has_big_component) ||
CheckSegmentDistance(input_coordinate, segment, max_distance);
});
if (results.size() == 0)
{
return std::make_pair(PhantomNode{}, PhantomNode{});
}
BOOST_ASSERT(results.size() > 0);
return std::make_pair(MakePhantomNode(input_coordinate, results.front()).phantom_node,
MakePhantomNode(input_coordinate, results.back()).phantom_node);
} }
private: private:
PhantomCandidateAlternatives
MakeAlternativeBigCandidates(const util::Coordinate input_coordinate,
const Coordinate nearest_coord,
const std::vector<CandidateSegment> &results) const
{
if (results.size() == 0)
{
return std::make_pair(PhantomNodeCandidates{}, PhantomNodeCandidates{});
}
PhantomNodeCandidates nearest_phantoms;
PhantomNodeCandidates big_component_phantoms;
const auto add_to_candidates = [this, &input_coordinate](PhantomNodeCandidates &candidates,
const EdgeData data) {
auto candidate_it =
std::find_if(candidates.begin(), candidates.end(), [&](const PhantomNode &node) {
return data.forward_segment_id.id == node.forward_segment_id.id &&
data.reverse_segment_id.id == node.reverse_segment_id.id;
});
if (candidate_it == candidates.end())
{
// First candidate from this segment
candidates.push_back(MakePhantomNode(input_coordinate, data).phantom_node);
}
else
{
/**
* Second candidate from this segment (there can be at most two).
* We're snapping at the connection between two edges e1,e2 of the segment.
*
* | e1 | e2 |
* | --- f1 --> | --- f2 --> |
* | <-- r1 --- | <-- r2 --- |
*
* Most of the routing algorithms only support one candidate from each segment.
* Therefore, we have to choose between e1 and e2.
*
* It makes sense to pick one edge over another if that edge offers more
* opportunities to act as a source or target for a route.
*
* For consistency, we use the following logic:
* "Pick e1 unless it makes sense to choose e2"
*
* Representing edge enabled as a truth table:
* f1 | r1 | f2 | r2 | selected
* ____________________________
* t | t | t | t | e1
* t | t | t | f | e1
* t | t | f | t | e1
* t | f | t | t | e2
* t | f | t | f | e1
* t | f | f | t | e1
* f | t | t | t | e2
* f | t | t | f | e1
* f | t | f | t | e1
*
* The other rows in truth table don't appear as we discard an edge if both
* forward and reverse are disabled.
*
**/
if (candidate_it->fwd_segment_position < data.fwd_segment_position)
{
if (data.forward_segment_id.enabled && data.reverse_segment_id.enabled &&
!(candidate_it->forward_segment_id.enabled &&
candidate_it->reverse_segment_id.enabled))
{
*candidate_it = MakePhantomNode(input_coordinate, data).phantom_node;
}
}
else
{
if (!candidate_it->forward_segment_id.enabled ||
!candidate_it->reverse_segment_id.enabled ||
(data.forward_segment_id.enabled && data.reverse_segment_id.enabled))
{
*candidate_it = MakePhantomNode(input_coordinate, data).phantom_node;
}
}
}
};
std::for_each(results.begin(), results.end(), [&](const CandidateSegment &segment) {
if (segment.fixed_projected_coordinate == nearest_coord)
{
add_to_candidates(nearest_phantoms, segment.data);
}
else
{
// Can only be from a big component for the alternative candidates
add_to_candidates(big_component_phantoms, segment.data);
}
});
return std::make_pair(std::move(nearest_phantoms), std::move(big_component_phantoms));
}
std::vector<PhantomNodeWithDistance> std::vector<PhantomNodeWithDistance>
MakePhantomNodes(const util::Coordinate input_coordinate, MakePhantomNodes(const util::Coordinate input_coordinate,
const std::vector<EdgeData> &results) const const std::vector<CandidateSegment> &results) const
{ {
std::vector<PhantomNodeWithDistance> distance_and_phantoms(results.size()); std::vector<PhantomNodeWithDistance> distance_and_phantoms(results.size());
std::transform(results.begin(), std::transform(results.begin(),
results.end(), results.end(),
distance_and_phantoms.begin(), distance_and_phantoms.begin(),
[this, &input_coordinate](const EdgeData &data) { [this, &input_coordinate](const CandidateSegment &segment) {
return MakePhantomNode(input_coordinate, data); return MakePhantomNode(input_coordinate, segment.data);
}); });
return distance_and_phantoms; return distance_and_phantoms;
} }
@ -580,9 +432,8 @@ template <typename RTreeT, typename DataFacadeT> class GeospatialQuery
return transformed; return transformed;
} }
bool CheckSegmentDistance(const Coordinate input_coordinate, double GetSegmentDistance(const Coordinate input_coordinate,
const CandidateSegment &segment, const CandidateSegment &segment) const
const double max_distance) const
{ {
BOOST_ASSERT(segment.data.forward_segment_id.id != SPECIAL_SEGMENTID || BOOST_ASSERT(segment.data.forward_segment_id.id != SPECIAL_SEGMENTID ||
!segment.data.forward_segment_id.enabled); !segment.data.forward_segment_id.enabled);
@ -593,7 +444,14 @@ template <typename RTreeT, typename DataFacadeT> class GeospatialQuery
util::web_mercator::toWGS84(segment.fixed_projected_coordinate); util::web_mercator::toWGS84(segment.fixed_projected_coordinate);
return util::coordinate_calculation::greatCircleDistance(input_coordinate, return util::coordinate_calculation::greatCircleDistance(input_coordinate,
wsg84_coordinate) > max_distance; wsg84_coordinate);
}
bool CheckSegmentDistance(const Coordinate input_coordinate,
const CandidateSegment &segment,
const double max_distance) const
{
return GetSegmentDistance(input_coordinate, segment) > max_distance;
} }
std::pair<bool, bool> CheckSegmentExclude(const CandidateSegment &segment) const std::pair<bool, bool> CheckSegmentExclude(const CandidateSegment &segment) const
@ -616,8 +474,7 @@ template <typename RTreeT, typename DataFacadeT> class GeospatialQuery
} }
std::pair<bool, bool> CheckSegmentBearing(const CandidateSegment &segment, std::pair<bool, bool> CheckSegmentBearing(const CandidateSegment &segment,
const int filter_bearing, const Bearing filter_bearing) const
const int filter_bearing_range) const
{ {
BOOST_ASSERT(segment.data.forward_segment_id.id != SPECIAL_SEGMENTID || BOOST_ASSERT(segment.data.forward_segment_id.id != SPECIAL_SEGMENTID ||
!segment.data.forward_segment_id.enabled); !segment.data.forward_segment_id.enabled);
@ -633,11 +490,11 @@ template <typename RTreeT, typename DataFacadeT> class GeospatialQuery
const bool forward_bearing_valid = const bool forward_bearing_valid =
util::bearing::CheckInBounds( util::bearing::CheckInBounds(
std::round(forward_edge_bearing), filter_bearing, filter_bearing_range) && std::round(forward_edge_bearing), filter_bearing.bearing, filter_bearing.range) &&
segment.data.forward_segment_id.enabled; segment.data.forward_segment_id.enabled;
const bool backward_bearing_valid = const bool backward_bearing_valid =
util::bearing::CheckInBounds( util::bearing::CheckInBounds(
std::round(backward_edge_bearing), filter_bearing, filter_bearing_range) && std::round(backward_edge_bearing), filter_bearing.bearing, filter_bearing.range) &&
segment.data.reverse_segment_id.enabled; segment.data.reverse_segment_id.enabled;
return std::make_pair(forward_bearing_valid, backward_bearing_valid); return std::make_pair(forward_bearing_valid, backward_bearing_valid);
} }
@ -645,7 +502,7 @@ template <typename RTreeT, typename DataFacadeT> class GeospatialQuery
/** /**
* Checks to see if the edge weights are valid. We might have an edge, * Checks to see if the edge weights are valid. We might have an edge,
* but a traffic update might set the speed to 0 (weight == INVALID_SEGMENT_WEIGHT). * but a traffic update might set the speed to 0 (weight == INVALID_SEGMENT_WEIGHT).
* which means that this edge is not currently traversible. If this is the case, * which means that this edge is not currently traversable. If this is the case,
* then we shouldn't snap to this edge. * then we shouldn't snap to this edge.
*/ */
std::pair<bool, bool> HasValidEdge(const CandidateSegment &segment, std::pair<bool, bool> HasValidEdge(const CandidateSegment &segment,
@ -682,7 +539,7 @@ template <typename RTreeT, typename DataFacadeT> class GeospatialQuery
bool IsTinyComponent(const CandidateSegment &segment) const bool IsTinyComponent(const CandidateSegment &segment) const
{ {
const auto &data = segment.data; const auto &data = segment.data;
BOOST_ASSERT(data.forward_segment_id.enabled); BOOST_ASSERT(data.forward_segment_id.enabled || data.reverse_segment_id.enabled);
BOOST_ASSERT(data.forward_segment_id.id != SPECIAL_NODEID); BOOST_ASSERT(data.forward_segment_id.id != SPECIAL_NODEID);
return datafacade.GetComponentID(data.forward_segment_id.id).is_tiny; return datafacade.GetComponentID(data.forward_segment_id.id).is_tiny;
} }

View File

@ -47,8 +47,9 @@ namespace datafacade
class BaseDataFacade; class BaseDataFacade;
} }
// Is returned as a temporary identifier for snapped coodinates // SegmentHint represents an individual segment position that could be used
struct Hint // as the waypoint for a given input location
struct SegmentHint
{ {
PhantomNode phantom; PhantomNode phantom;
std::uint32_t data_checksum; std::uint32_t data_checksum;
@ -57,16 +58,31 @@ struct Hint
const datafacade::BaseDataFacade &facade) const; const datafacade::BaseDataFacade &facade) const;
std::string ToBase64() const; std::string ToBase64() const;
static Hint FromBase64(const std::string &base64Hint); static SegmentHint FromBase64(const std::string &base64Hint);
friend bool operator==(const Hint &, const Hint &); friend bool operator==(const SegmentHint &, const SegmentHint &);
friend std::ostream &operator<<(std::ostream &, const Hint &); friend bool operator!=(const SegmentHint &, const SegmentHint &);
friend std::ostream &operator<<(std::ostream &, const SegmentHint &);
}; };
static_assert(sizeof(Hint) == 80 + 4, "Hint is bigger than expected"); // Hint represents the suggested segment positions that could be used
constexpr std::size_t ENCODED_HINT_SIZE = 112; // as the waypoint for a given input location
static_assert(ENCODED_HINT_SIZE / 4 * 3 >= sizeof(Hint), struct Hint
"ENCODED_HINT_SIZE does not match size of Hint"); {
std::vector<SegmentHint> segment_hints;
bool IsValid(const util::Coordinate new_input_coordinates,
const datafacade::BaseDataFacade &facade) const;
std::string ToBase64() const;
static Hint FromBase64(const std::string &base64Hint);
};
static_assert(sizeof(SegmentHint) == 80 + 4, "Hint is bigger than expected");
constexpr std::size_t ENCODED_SEGMENT_HINT_SIZE = 112;
static_assert(ENCODED_SEGMENT_HINT_SIZE / 4 * 3 >= sizeof(SegmentHint),
"ENCODED_SEGMENT_HINT_SIZE does not match size of SegmentHint");
} // namespace engine } // namespace engine
} // namespace osrm } // namespace osrm

View File

@ -50,7 +50,7 @@ struct PathData
struct InternalRouteResult struct InternalRouteResult
{ {
std::vector<std::vector<PathData>> unpacked_path_segments; std::vector<std::vector<PathData>> unpacked_path_segments;
std::vector<PhantomNodes> segment_end_coordinates; std::vector<PhantomEndpoints> leg_endpoints;
std::vector<bool> source_traversed_in_reverse; std::vector<bool> source_traversed_in_reverse;
std::vector<bool> target_traversed_in_reverse; std::vector<bool> target_traversed_in_reverse;
EdgeWeight shortest_path_weight = INVALID_EDGE_WEIGHT; EdgeWeight shortest_path_weight = INVALID_EDGE_WEIGHT;
@ -96,7 +96,7 @@ inline InternalRouteResult CollapseInternalRouteResult(const InternalRouteResult
if (leggy_result.unpacked_path_segments.size() == 1) if (leggy_result.unpacked_path_segments.size() == 1)
return leggy_result; return leggy_result;
BOOST_ASSERT(leggy_result.segment_end_coordinates.size() > 1); BOOST_ASSERT(leggy_result.leg_endpoints.size() > 1);
InternalRouteResult collapsed; InternalRouteResult collapsed;
collapsed.shortest_path_weight = leggy_result.shortest_path_weight; collapsed.shortest_path_weight = leggy_result.shortest_path_weight;
@ -107,7 +107,7 @@ inline InternalRouteResult CollapseInternalRouteResult(const InternalRouteResult
// start another leg vector // start another leg vector
collapsed.unpacked_path_segments.push_back(leggy_result.unpacked_path_segments[i]); collapsed.unpacked_path_segments.push_back(leggy_result.unpacked_path_segments[i]);
// save new phantom node pair // save new phantom node pair
collapsed.segment_end_coordinates.push_back(leggy_result.segment_end_coordinates[i]); collapsed.leg_endpoints.push_back(leggy_result.leg_endpoints[i]);
// save data about phantom nodes // save data about phantom nodes
collapsed.source_traversed_in_reverse.push_back( collapsed.source_traversed_in_reverse.push_back(
leggy_result.source_traversed_in_reverse[i]); leggy_result.source_traversed_in_reverse[i]);
@ -119,9 +119,9 @@ inline InternalRouteResult CollapseInternalRouteResult(const InternalRouteResult
{ {
BOOST_ASSERT(!collapsed.unpacked_path_segments.empty()); BOOST_ASSERT(!collapsed.unpacked_path_segments.empty());
auto &last_segment = collapsed.unpacked_path_segments.back(); auto &last_segment = collapsed.unpacked_path_segments.back();
BOOST_ASSERT(!collapsed.segment_end_coordinates.empty()); BOOST_ASSERT(!collapsed.leg_endpoints.empty());
collapsed.segment_end_coordinates.back().target_phantom = collapsed.leg_endpoints.back().target_phantom =
leggy_result.segment_end_coordinates[i].target_phantom; leggy_result.leg_endpoints[i].target_phantom;
collapsed.target_traversed_in_reverse.back() = collapsed.target_traversed_in_reverse.back() =
leggy_result.target_traversed_in_reverse[i]; leggy_result.target_traversed_in_reverse[i];
// copy path segments into current leg // copy path segments into current leg
@ -138,19 +138,18 @@ inline InternalRouteResult CollapseInternalRouteResult(const InternalRouteResult
last_segment[old_size].weight_until_turn += last_segment[old_size].weight_until_turn +=
leggy_result.source_traversed_in_reverse[i] leggy_result.source_traversed_in_reverse[i]
? leggy_result.segment_end_coordinates[i].source_phantom.reverse_weight ? leggy_result.leg_endpoints[i].source_phantom.reverse_weight
: leggy_result.segment_end_coordinates[i].source_phantom.forward_weight; : leggy_result.leg_endpoints[i].source_phantom.forward_weight;
last_segment[old_size].duration_until_turn += last_segment[old_size].duration_until_turn +=
leggy_result.source_traversed_in_reverse[i] leggy_result.source_traversed_in_reverse[i]
? leggy_result.segment_end_coordinates[i].source_phantom.reverse_duration ? leggy_result.leg_endpoints[i].source_phantom.reverse_duration
: leggy_result.segment_end_coordinates[i].source_phantom.forward_duration; : leggy_result.leg_endpoints[i].source_phantom.forward_duration;
} }
} }
} }
BOOST_ASSERT(collapsed.segment_end_coordinates.size() == BOOST_ASSERT(collapsed.leg_endpoints.size() == collapsed.unpacked_path_segments.size());
collapsed.unpacked_path_segments.size());
return collapsed; return collapsed;
} }
} // namespace engine } // namespace engine

View File

@ -28,6 +28,8 @@ SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
#ifndef OSRM_ENGINE_PHANTOM_NODES_H #ifndef OSRM_ENGINE_PHANTOM_NODES_H
#define OSRM_ENGINE_PHANTOM_NODES_H #define OSRM_ENGINE_PHANTOM_NODES_H
#include <vector>
#include "extractor/travel_mode.hpp" #include "extractor/travel_mode.hpp"
#include "util/bearing.hpp" #include "util/bearing.hpp"
@ -223,7 +225,8 @@ struct PhantomNode
static_assert(sizeof(PhantomNode) == 80, "PhantomNode has more padding then expected"); static_assert(sizeof(PhantomNode) == 80, "PhantomNode has more padding then expected");
using PhantomNodePair = std::pair<PhantomNode, PhantomNode>; using PhantomNodeCandidates = std::vector<PhantomNode>;
using PhantomCandidateAlternatives = std::pair<PhantomNodeCandidates, PhantomNodeCandidates>;
struct PhantomNodeWithDistance struct PhantomNodeWithDistance
{ {
@ -231,11 +234,44 @@ struct PhantomNodeWithDistance
double distance; double distance;
}; };
struct PhantomNodes struct PhantomEndpointCandidates
{
const PhantomNodeCandidates &source_phantoms;
const PhantomNodeCandidates &target_phantoms;
};
struct PhantomCandidatesToTarget
{
const PhantomNodeCandidates &source_phantoms;
const PhantomNode &target_phantom;
};
inline util::Coordinate candidatesSnappedLocation(const PhantomNodeCandidates &candidates)
{
BOOST_ASSERT(!candidates.empty());
return candidates.front().location;
}
inline util::Coordinate candidatesInputLocation(const PhantomNodeCandidates &candidates)
{
BOOST_ASSERT(!candidates.empty());
return candidates.front().input_location;
}
inline bool candidatesHaveComponent(const PhantomNodeCandidates &candidates, uint32_t component_id)
{
return std::any_of(
candidates.begin(), candidates.end(), [component_id](const PhantomNode &node) {
return node.component.id == component_id;
});
}
struct PhantomEndpoints
{ {
PhantomNode source_phantom; PhantomNode source_phantom;
PhantomNode target_phantom; PhantomNode target_phantom;
}; };
} // namespace engine } // namespace engine
} // namespace osrm } // namespace osrm

View File

@ -99,64 +99,67 @@ class BasePlugin
return Status::Error; return Status::Error;
} }
// Decides whether to use the phantom node from a big or small component if both are found. // Decides whether to use the phantom candidates from big or small components if both are found.
// Returns true if all phantom nodes are in the same component after snapping. std::vector<PhantomNodeCandidates>
std::vector<PhantomNode> SnapPhantomNodes(std::vector<PhantomCandidateAlternatives> alternatives_list) const
SnapPhantomNodes(const std::vector<PhantomNodePair> &phantom_node_pair_list) const
{ {
const auto check_component_id_is_tiny =
[](const std::pair<PhantomNode, PhantomNode> &phantom_pair) {
return phantom_pair.first.component.is_tiny;
};
// are all phantoms from a tiny cc? // are all phantoms from a tiny cc?
const auto check_all_in_same_component = const auto all_in_same_tiny_component =
[](const std::vector<std::pair<PhantomNode, PhantomNode>> &nodes) { [](const std::vector<PhantomCandidateAlternatives> &alts_list) {
const auto component_id = nodes.front().first.component.id; return std::any_of(
alts_list.front().first.begin(),
return std::all_of(std::begin(nodes), alts_list.front().first.end(),
std::end(nodes), // For each of the first possible phantoms, check if all other
[component_id](const PhantomNodePair &phantom_pair) { // positions in the list have a phantom from the same small component.
return component_id == phantom_pair.first.component.id; [&](const PhantomNode &phantom) {
if (!phantom.component.is_tiny)
{
return false;
}
const auto component_id = phantom.component.id;
return std::all_of(
std::next(alts_list.begin()),
std::end(alts_list),
[component_id](const PhantomCandidateAlternatives &alternatives) {
return candidatesHaveComponent(alternatives.first, component_id);
});
}); });
}; };
const auto fallback_to_big_component = // Move the alternative into the final list
[](const std::pair<PhantomNode, PhantomNode> &phantom_pair) { const auto fallback_to_big_component = [](PhantomCandidateAlternatives &alternatives) {
if (phantom_pair.first.component.is_tiny && phantom_pair.second.IsValid() && auto no_big_alternative = alternatives.second.empty();
!phantom_pair.second.component.is_tiny) return no_big_alternative ? std::move(alternatives.first)
{ : std::move(alternatives.second);
return phantom_pair.second;
}
return phantom_pair.first;
}; };
const auto use_closed_phantom = // Move the alternative into the final list
[](const std::pair<PhantomNode, PhantomNode> &phantom_pair) { const auto use_closed_phantom = [](PhantomCandidateAlternatives &alternatives) {
return phantom_pair.first; return std::move(alternatives.first);
}; };
const bool every_phantom_is_in_tiny_cc = std::all_of(std::begin(phantom_node_pair_list), const auto no_alternatives =
std::end(phantom_node_pair_list), std::all_of(alternatives_list.begin(),
check_component_id_is_tiny); alternatives_list.end(),
auto all_in_same_component = check_all_in_same_component(phantom_node_pair_list); [](const PhantomCandidateAlternatives &alternatives) {
return alternatives.second.empty();
std::vector<PhantomNode> snapped_phantoms; });
snapped_phantoms.reserve(phantom_node_pair_list.size());
std::vector<PhantomNodeCandidates> snapped_phantoms;
snapped_phantoms.reserve(alternatives_list.size());
// The only case we don't snap to the big component if all phantoms are in the same small // The only case we don't snap to the big component if all phantoms are in the same small
// component // component
if (every_phantom_is_in_tiny_cc && all_in_same_component) if (no_alternatives || all_in_same_tiny_component(alternatives_list))
{ {
std::transform(phantom_node_pair_list.begin(), std::transform(alternatives_list.begin(),
phantom_node_pair_list.end(), alternatives_list.end(),
std::back_inserter(snapped_phantoms), std::back_inserter(snapped_phantoms),
use_closed_phantom); use_closed_phantom);
} }
else else
{ {
std::transform(phantom_node_pair_list.begin(), std::transform(alternatives_list.begin(),
phantom_node_pair_list.end(), alternatives_list.end(),
std::back_inserter(snapped_phantoms), std::back_inserter(snapped_phantoms),
fallback_to_big_component); fallback_to_big_component);
} }
@ -181,35 +184,26 @@ class BasePlugin
for (const auto i : util::irange<std::size_t>(0UL, parameters.coordinates.size())) for (const auto i : util::irange<std::size_t>(0UL, parameters.coordinates.size()))
{ {
Approach approach = engine::Approach::UNRESTRICTED; if (use_hints && parameters.hints[i] && !parameters.hints[i]->segment_hints.empty() &&
if (use_approaches && parameters.approaches[i])
approach = parameters.approaches[i].get();
if (use_hints && parameters.hints[i] &&
parameters.hints[i]->IsValid(parameters.coordinates[i], facade)) parameters.hints[i]->IsValid(parameters.coordinates[i], facade))
{
for (const auto &seg_hint : parameters.hints[i]->segment_hints)
{ {
phantom_nodes[i].push_back(PhantomNodeWithDistance{ phantom_nodes[i].push_back(PhantomNodeWithDistance{
parameters.hints[i]->phantom, seg_hint.phantom,
util::coordinate_calculation::greatCircleDistance( util::coordinate_calculation::greatCircleDistance(
parameters.coordinates[i], parameters.hints[i]->phantom.location), parameters.coordinates[i], seg_hint.phantom.location)});
}); }
continue; continue;
} }
if (use_bearings && parameters.bearings[i])
{
phantom_nodes[i] =
facade.NearestPhantomNodesInRange(parameters.coordinates[i],
radiuses[i],
parameters.bearings[i]->bearing,
parameters.bearings[i]->range,
approach,
use_all_edges);
}
else
{
phantom_nodes[i] = facade.NearestPhantomNodesInRange( phantom_nodes[i] = facade.NearestPhantomNodesInRange(
parameters.coordinates[i], radiuses[i], approach, use_all_edges); parameters.coordinates[i],
} radiuses[i],
use_bearings ? parameters.bearings[i] : boost::none,
use_approaches && parameters.approaches[i] ? parameters.approaches[i].get()
: engine::Approach::UNRESTRICTED,
use_all_edges);
} }
return phantom_nodes; return phantom_nodes;
@ -218,7 +212,7 @@ class BasePlugin
std::vector<std::vector<PhantomNodeWithDistance>> std::vector<std::vector<PhantomNodeWithDistance>>
GetPhantomNodes(const datafacade::BaseDataFacade &facade, GetPhantomNodes(const datafacade::BaseDataFacade &facade,
const api::BaseParameters &parameters, const api::BaseParameters &parameters,
unsigned number_of_results) const size_t number_of_results) const
{ {
std::vector<std::vector<PhantomNodeWithDistance>> phantom_nodes( std::vector<std::vector<PhantomNodeWithDistance>> phantom_nodes(
parameters.coordinates.size()); parameters.coordinates.size());
@ -231,56 +225,26 @@ class BasePlugin
BOOST_ASSERT(parameters.IsValid()); BOOST_ASSERT(parameters.IsValid());
for (const auto i : util::irange<std::size_t>(0UL, parameters.coordinates.size())) for (const auto i : util::irange<std::size_t>(0UL, parameters.coordinates.size()))
{ {
Approach approach = engine::Approach::UNRESTRICTED; if (use_hints && parameters.hints[i] && !parameters.hints[i]->segment_hints.empty() &&
if (use_approaches && parameters.approaches[i])
approach = parameters.approaches[i].get();
if (use_hints && parameters.hints[i] &&
parameters.hints[i]->IsValid(parameters.coordinates[i], facade)) parameters.hints[i]->IsValid(parameters.coordinates[i], facade))
{
for (const auto &seg_hint : parameters.hints[i]->segment_hints)
{ {
phantom_nodes[i].push_back(PhantomNodeWithDistance{ phantom_nodes[i].push_back(PhantomNodeWithDistance{
parameters.hints[i]->phantom, seg_hint.phantom,
util::coordinate_calculation::greatCircleDistance( util::coordinate_calculation::greatCircleDistance(
parameters.coordinates[i], parameters.hints[i]->phantom.location), parameters.coordinates[i], seg_hint.phantom.location)});
}); }
continue; continue;
} }
if (use_bearings && parameters.bearings[i])
{
if (use_radiuses && parameters.radiuses[i])
{
phantom_nodes[i] = facade.NearestPhantomNodes(parameters.coordinates[i],
number_of_results,
*parameters.radiuses[i],
parameters.bearings[i]->bearing,
parameters.bearings[i]->range,
approach);
}
else
{
phantom_nodes[i] = facade.NearestPhantomNodes(parameters.coordinates[i],
number_of_results,
parameters.bearings[i]->bearing,
parameters.bearings[i]->range,
approach);
}
}
else
{
if (use_radiuses && parameters.radiuses[i])
{
phantom_nodes[i] = facade.NearestPhantomNodes(parameters.coordinates[i],
number_of_results,
*parameters.radiuses[i],
approach);
}
else
{
phantom_nodes[i] = facade.NearestPhantomNodes( phantom_nodes[i] = facade.NearestPhantomNodes(
parameters.coordinates[i], number_of_results, approach); parameters.coordinates[i],
} number_of_results,
} use_radiuses ? parameters.radiuses[i] : boost::none,
use_bearings ? parameters.bearings[i] : boost::none,
use_approaches && parameters.approaches[i] ? parameters.approaches[i].get()
: engine::Approach::UNRESTRICTED);
// we didn't find a fitting node, return error // we didn't find a fitting node, return error
if (phantom_nodes[i].empty()) if (phantom_nodes[i].empty())
@ -291,10 +255,11 @@ class BasePlugin
return phantom_nodes; return phantom_nodes;
} }
std::vector<PhantomNodePair> GetPhantomNodes(const datafacade::BaseDataFacade &facade, std::vector<PhantomCandidateAlternatives>
GetPhantomNodes(const datafacade::BaseDataFacade &facade,
const api::BaseParameters &parameters) const const api::BaseParameters &parameters) const
{ {
std::vector<PhantomNodePair> phantom_node_pairs(parameters.coordinates.size()); std::vector<PhantomCandidateAlternatives> alternatives(parameters.coordinates.size());
const bool use_hints = !parameters.hints.empty(); const bool use_hints = !parameters.hints.empty();
const bool use_bearings = !parameters.bearings.empty(); const bool use_bearings = !parameters.bearings.empty();
@ -305,87 +270,57 @@ class BasePlugin
BOOST_ASSERT(parameters.IsValid()); BOOST_ASSERT(parameters.IsValid());
for (const auto i : util::irange<std::size_t>(0UL, parameters.coordinates.size())) for (const auto i : util::irange<std::size_t>(0UL, parameters.coordinates.size()))
{ {
Approach approach = engine::Approach::UNRESTRICTED; if (use_hints && parameters.hints[i] && !parameters.hints[i]->segment_hints.empty() &&
if (use_approaches && parameters.approaches[i])
approach = parameters.approaches[i].get();
if (use_hints && parameters.hints[i] &&
parameters.hints[i]->IsValid(parameters.coordinates[i], facade)) parameters.hints[i]->IsValid(parameters.coordinates[i], facade))
{ {
phantom_node_pairs[i].first = parameters.hints[i]->phantom; std::transform(parameters.hints[i]->segment_hints.begin(),
parameters.hints[i]->segment_hints.end(),
std::back_inserter(alternatives[i].first),
[](const auto &seg_hint) { return seg_hint.phantom; });
// we don't set the second one - it will be marked as invalid // we don't set the second one - it will be marked as invalid
continue; continue;
} }
if (use_bearings && parameters.bearings[i]) alternatives[i] = facade.NearestCandidatesWithAlternativeFromBigComponent(
{
if (use_radiuses && parameters.radiuses[i])
{
phantom_node_pairs[i] =
facade.NearestPhantomNodeWithAlternativeFromBigComponent(
parameters.coordinates[i], parameters.coordinates[i],
*parameters.radiuses[i], use_radiuses ? parameters.radiuses[i] : boost::none,
parameters.bearings[i]->bearing, use_bearings ? parameters.bearings[i] : boost::none,
parameters.bearings[i]->range, use_approaches && parameters.approaches[i] ? parameters.approaches[i].get()
approach, : engine::Approach::UNRESTRICTED,
use_all_edges); use_all_edges);
}
else
{
phantom_node_pairs[i] =
facade.NearestPhantomNodeWithAlternativeFromBigComponent(
parameters.coordinates[i],
parameters.bearings[i]->bearing,
parameters.bearings[i]->range,
approach,
use_all_edges);
}
}
else
{
if (use_radiuses && parameters.radiuses[i])
{
phantom_node_pairs[i] =
facade.NearestPhantomNodeWithAlternativeFromBigComponent(
parameters.coordinates[i],
*parameters.radiuses[i],
approach,
use_all_edges);
}
else
{
phantom_node_pairs[i] =
facade.NearestPhantomNodeWithAlternativeFromBigComponent(
parameters.coordinates[i], approach, use_all_edges);
}
}
// we didn't find a fitting node, return error // we didn't find a fitting node, return error
if (!phantom_node_pairs[i].first.IsValid()) if (alternatives[i].first.empty())
{ {
// This ensures the list of phantom nodes only consists of valid nodes. // This ensures the list of phantom nodes only consists of valid nodes.
// We can use this on the call-site to detect an error. // We can use this on the call-site to detect an error.
phantom_node_pairs.pop_back(); alternatives.pop_back();
break; break;
} }
BOOST_ASSERT(phantom_node_pairs[i].first.IsValid());
BOOST_ASSERT(phantom_node_pairs[i].second.IsValid()); BOOST_ASSERT(!alternatives[i].first.empty());
} }
return phantom_node_pairs; return alternatives;
} }
std::string MissingPhantomErrorMessage(const std::vector<PhantomNodePair> &phantom_nodes, std::string
MissingPhantomErrorMessage(const std::vector<PhantomCandidateAlternatives> &alternatives,
const std::vector<util::Coordinate> &coordinates) const const std::vector<util::Coordinate> &coordinates) const
{ {
BOOST_ASSERT(phantom_nodes.size() < coordinates.size()); BOOST_ASSERT(alternatives.size() < coordinates.size());
auto mismatch = std::mismatch(phantom_nodes.begin(), auto mismatch =
phantom_nodes.end(), std::mismatch(alternatives.begin(),
alternatives.end(),
coordinates.begin(), coordinates.begin(),
coordinates.end(), coordinates.end(),
[](const auto &phantom_node, const auto &coordinate) { [](const auto &candidates_pair, const auto &coordinate) {
return phantom_node.first.input_location == coordinate; return std::any_of(candidates_pair.first.begin(),
candidates_pair.first.end(),
[&](const auto &phantom) {
return phantom.input_location == coordinate;
}); });
std::size_t missing_index = std::distance(phantom_nodes.begin(), mismatch.first); });
std::size_t missing_index = std::distance(alternatives.begin(), mismatch.first);
return std::string("Could not find a matching segment for coordinate ") + return std::string("Could not find a matching segment for coordinate ") +
std::to_string(missing_index); std::to_string(missing_index);
} }

View File

@ -31,7 +31,7 @@ class TripPlugin final : public BasePlugin
const int max_locations_trip; const int max_locations_trip;
InternalRouteResult ComputeRoute(const RoutingAlgorithmsInterface &algorithms, InternalRouteResult ComputeRoute(const RoutingAlgorithmsInterface &algorithms,
const std::vector<PhantomNode> &phantom_node_list, const std::vector<PhantomNodeCandidates> &candidates_list,
const std::vector<NodeID> &trip, const std::vector<NodeID> &trip,
const bool roundtrip) const; const bool roundtrip) const;

View File

@ -20,18 +20,18 @@ class RoutingAlgorithmsInterface
{ {
public: public:
virtual InternalManyRoutesResult virtual InternalManyRoutesResult
AlternativePathSearch(const PhantomNodes &phantom_node_pair, AlternativePathSearch(const PhantomEndpointCandidates &endpoint_candidates,
unsigned number_of_alternatives) const = 0; unsigned number_of_alternatives) const = 0;
virtual InternalRouteResult virtual InternalRouteResult
ShortestPathSearch(const std::vector<PhantomNodes> &phantom_node_pair, ShortestPathSearch(const std::vector<PhantomNodeCandidates> &waypoint_candidates,
const boost::optional<bool> continue_straight_at_waypoint) const = 0; const boost::optional<bool> continue_straight_at_waypoint) const = 0;
virtual InternalRouteResult virtual InternalRouteResult
DirectShortestPathSearch(const PhantomNodes &phantom_node_pair) const = 0; DirectShortestPathSearch(const PhantomEndpointCandidates &endpoint_candidates) const = 0;
virtual std::pair<std::vector<EdgeDuration>, std::vector<EdgeDistance>> virtual std::pair<std::vector<EdgeDuration>, std::vector<EdgeDistance>>
ManyToManySearch(const std::vector<PhantomNode> &phantom_nodes, ManyToManySearch(const std::vector<PhantomNodeCandidates> &candidates_list,
const std::vector<std::size_t> &source_indices, const std::vector<std::size_t> &source_indices,
const std::vector<std::size_t> &target_indices, const std::vector<std::size_t> &target_indices,
const bool calculate_distance) const = 0; const bool calculate_distance) const = 0;
@ -73,18 +73,18 @@ template <typename Algorithm> class RoutingAlgorithms final : public RoutingAlgo
virtual ~RoutingAlgorithms() = default; virtual ~RoutingAlgorithms() = default;
InternalManyRoutesResult InternalManyRoutesResult
AlternativePathSearch(const PhantomNodes &phantom_node_pair, AlternativePathSearch(const PhantomEndpointCandidates &endpoint_candidates,
unsigned number_of_alternatives) const final override; unsigned number_of_alternatives) const final override;
InternalRouteResult ShortestPathSearch( InternalRouteResult ShortestPathSearch(
const std::vector<PhantomNodes> &phantom_node_pair, const std::vector<PhantomNodeCandidates> &waypoint_candidates,
const boost::optional<bool> continue_straight_at_waypoint) const final override; const boost::optional<bool> continue_straight_at_waypoint) const final override;
InternalRouteResult InternalRouteResult DirectShortestPathSearch(
DirectShortestPathSearch(const PhantomNodes &phantom_nodes) const final override; const PhantomEndpointCandidates &endpoint_candidates) const final override;
virtual std::pair<std::vector<EdgeDuration>, std::vector<EdgeDistance>> std::pair<std::vector<EdgeDuration>, std::vector<EdgeDistance>>
ManyToManySearch(const std::vector<PhantomNode> &phantom_nodes, ManyToManySearch(const std::vector<PhantomNodeCandidates> &candidates_list,
const std::vector<std::size_t> &source_indices, const std::vector<std::size_t> &source_indices,
const std::vector<std::size_t> &target_indices, const std::vector<std::size_t> &target_indices,
const bool calculate_distance) const final override; const bool calculate_distance) const final override;
@ -150,28 +150,27 @@ template <typename Algorithm> class RoutingAlgorithms final : public RoutingAlgo
}; };
template <typename Algorithm> template <typename Algorithm>
InternalManyRoutesResult InternalManyRoutesResult RoutingAlgorithms<Algorithm>::AlternativePathSearch(
RoutingAlgorithms<Algorithm>::AlternativePathSearch(const PhantomNodes &phantom_node_pair, const PhantomEndpointCandidates &endpoint_candidates, unsigned number_of_alternatives) const
unsigned number_of_alternatives) const
{ {
return routing_algorithms::alternativePathSearch( return routing_algorithms::alternativePathSearch(
heaps, *facade, phantom_node_pair, number_of_alternatives); heaps, *facade, endpoint_candidates, number_of_alternatives);
} }
template <typename Algorithm> template <typename Algorithm>
InternalRouteResult RoutingAlgorithms<Algorithm>::ShortestPathSearch( InternalRouteResult RoutingAlgorithms<Algorithm>::ShortestPathSearch(
const std::vector<PhantomNodes> &phantom_node_pair, const std::vector<PhantomNodeCandidates> &waypoint_candidates,
const boost::optional<bool> continue_straight_at_waypoint) const const boost::optional<bool> continue_straight_at_waypoint) const
{ {
return routing_algorithms::shortestPathSearch( return routing_algorithms::shortestPathSearch(
heaps, *facade, phantom_node_pair, continue_straight_at_waypoint); heaps, *facade, waypoint_candidates, continue_straight_at_waypoint);
} }
template <typename Algorithm> template <typename Algorithm>
InternalRouteResult InternalRouteResult RoutingAlgorithms<Algorithm>::DirectShortestPathSearch(
RoutingAlgorithms<Algorithm>::DirectShortestPathSearch(const PhantomNodes &phantom_nodes) const const PhantomEndpointCandidates &endpoint_candidates) const
{ {
return routing_algorithms::directShortestPathSearch(heaps, *facade, phantom_nodes); return routing_algorithms::directShortestPathSearch(heaps, *facade, endpoint_candidates);
} }
template <typename Algorithm> template <typename Algorithm>
@ -193,30 +192,31 @@ inline routing_algorithms::SubMatchingList RoutingAlgorithms<Algorithm>::MapMatc
template <typename Algorithm> template <typename Algorithm>
std::pair<std::vector<EdgeDuration>, std::vector<EdgeDistance>> std::pair<std::vector<EdgeDuration>, std::vector<EdgeDistance>>
RoutingAlgorithms<Algorithm>::ManyToManySearch(const std::vector<PhantomNode> &phantom_nodes, RoutingAlgorithms<Algorithm>::ManyToManySearch(
const std::vector<PhantomNodeCandidates> &candidates_list,
const std::vector<std::size_t> &_source_indices, const std::vector<std::size_t> &_source_indices,
const std::vector<std::size_t> &_target_indices, const std::vector<std::size_t> &_target_indices,
const bool calculate_distance) const const bool calculate_distance) const
{ {
BOOST_ASSERT(!phantom_nodes.empty()); BOOST_ASSERT(!candidates_list.empty());
auto source_indices = _source_indices; auto source_indices = _source_indices;
auto target_indices = _target_indices; auto target_indices = _target_indices;
if (source_indices.empty()) if (source_indices.empty())
{ {
source_indices.resize(phantom_nodes.size()); source_indices.resize(candidates_list.size());
std::iota(source_indices.begin(), source_indices.end(), 0); std::iota(source_indices.begin(), source_indices.end(), 0);
} }
if (target_indices.empty()) if (target_indices.empty())
{ {
target_indices.resize(phantom_nodes.size()); target_indices.resize(candidates_list.size());
std::iota(target_indices.begin(), target_indices.end(), 0); std::iota(target_indices.begin(), target_indices.end(), 0);
} }
return routing_algorithms::manyToManySearch(heaps, return routing_algorithms::manyToManySearch(heaps,
*facade, *facade,
phantom_nodes, candidates_list,
std::move(source_indices), std::move(source_indices),
std::move(target_indices), std::move(target_indices),
calculate_distance); calculate_distance);

View File

@ -18,12 +18,12 @@ namespace routing_algorithms
InternalManyRoutesResult alternativePathSearch(SearchEngineData<ch::Algorithm> &search_engine_data, InternalManyRoutesResult alternativePathSearch(SearchEngineData<ch::Algorithm> &search_engine_data,
const DataFacade<ch::Algorithm> &facade, const DataFacade<ch::Algorithm> &facade,
const PhantomNodes &phantom_node_pair, const PhantomEndpointCandidates &endpoint_candidates,
unsigned number_of_alternatives); unsigned number_of_alternatives);
InternalManyRoutesResult alternativePathSearch(SearchEngineData<mld::Algorithm> &search_engine_data, InternalManyRoutesResult alternativePathSearch(SearchEngineData<mld::Algorithm> &search_engine_data,
const DataFacade<mld::Algorithm> &facade, const DataFacade<mld::Algorithm> &facade,
const PhantomNodes &phantom_node_pair, const PhantomEndpointCandidates &endpoint_candidates,
unsigned number_of_alternatives); unsigned number_of_alternatives);
} // namespace routing_algorithms } // namespace routing_algorithms

View File

@ -24,7 +24,7 @@ namespace routing_algorithms
template <typename Algorithm> template <typename Algorithm>
InternalRouteResult directShortestPathSearch(SearchEngineData<Algorithm> &engine_working_data, InternalRouteResult directShortestPathSearch(SearchEngineData<Algorithm> &engine_working_data,
const DataFacade<Algorithm> &facade, const DataFacade<Algorithm> &facade,
const PhantomNodes &phantom_nodes); const PhantomEndpointCandidates &endpoint_candidates);
} // namespace routing_algorithms } // namespace routing_algorithms
} // namespace engine } // namespace engine

View File

@ -94,7 +94,7 @@ template <typename Algorithm>
std::pair<std::vector<EdgeDuration>, std::vector<EdgeDistance>> std::pair<std::vector<EdgeDuration>, std::vector<EdgeDistance>>
manyToManySearch(SearchEngineData<Algorithm> &engine_working_data, manyToManySearch(SearchEngineData<Algorithm> &engine_working_data,
const DataFacade<Algorithm> &facade, const DataFacade<Algorithm> &facade,
const std::vector<PhantomNode> &phantom_nodes, const std::vector<PhantomNodeCandidates> &candidates_list,
const std::vector<std::size_t> &source_indices, const std::vector<std::size_t> &source_indices,
const std::vector<std::size_t> &target_indices, const std::vector<std::size_t> &target_indices,
const bool calculate_distance); const bool calculate_distance);

View File

@ -34,20 +34,12 @@ namespace engine
namespace routing_algorithms namespace routing_algorithms
{ {
static constexpr bool FORWARD_DIRECTION = true;
static constexpr bool REVERSE_DIRECTION = false;
static constexpr bool DO_NOT_FORCE_LOOPS = false;
bool needsLoopForward(const PhantomNode &source_phantom, const PhantomNode &target_phantom); namespace details
bool needsLoopBackwards(const PhantomNode &source_phantom, const PhantomNode &target_phantom); {
template <typename Heap>
bool needsLoopForward(const PhantomNodes &phantoms); void insertSourceInForwardHeap(Heap &forward_heap, const PhantomNode &source)
bool needsLoopBackwards(const PhantomNodes &phantoms);
template <typename Heap>
void insertNodesInHeaps(Heap &forward_heap, Heap &reverse_heap, const PhantomNodes &nodes)
{ {
const auto &source = nodes.source_phantom;
if (source.IsValidForwardSource()) if (source.IsValidForwardSource())
{ {
forward_heap.Insert(source.forward_segment_id.id, forward_heap.Insert(source.forward_segment_id.id,
@ -61,8 +53,11 @@ void insertNodesInHeaps(Heap &forward_heap, Heap &reverse_heap, const PhantomNod
-source.GetReverseWeightPlusOffset(), -source.GetReverseWeightPlusOffset(),
source.reverse_segment_id.id); source.reverse_segment_id.id);
} }
}
const auto &target = nodes.target_phantom; template <typename Heap>
void insertTargetInReverseHeap(Heap &reverse_heap, const PhantomNode &target)
{
if (target.IsValidForwardTarget()) if (target.IsValidForwardTarget())
{ {
reverse_heap.Insert(target.forward_segment_id.id, reverse_heap.Insert(target.forward_segment_id.id,
@ -77,10 +72,58 @@ void insertNodesInHeaps(Heap &forward_heap, Heap &reverse_heap, const PhantomNod
target.reverse_segment_id.id); target.reverse_segment_id.id);
} }
} }
} // namespace details
static constexpr bool FORWARD_DIRECTION = true;
static constexpr bool REVERSE_DIRECTION = false;
// Identify nodes in the forward(reverse) search direction that will require loop forcing
// e.g. if source and destination nodes are on the same segment.
std::vector<NodeID> getForwardLoopNodes(const PhantomEndpointCandidates &candidates);
std::vector<NodeID> getForwardLoopNodes(const PhantomCandidatesToTarget &candidates);
std::vector<NodeID> getBackwardLoopNodes(const PhantomEndpointCandidates &candidates);
std::vector<NodeID> getBackwardLoopNodes(const PhantomCandidatesToTarget &candidates);
// Find the specific phantom node endpoints for a given path from a list of candidates.
PhantomEndpoints endpointsFromCandidates(const PhantomEndpointCandidates &candidates,
const std::vector<NodeID> &path);
template <typename HeapNodeT>
inline bool force_loop(const std::vector<NodeID> &force_nodes, const HeapNodeT &heap_node)
{
// if loops are forced, they are so at the source
return !force_nodes.empty() &&
std::find(force_nodes.begin(), force_nodes.end(), heap_node.node) != force_nodes.end() &&
heap_node.data.parent == heap_node.node;
}
template <typename Heap>
void insertNodesInHeaps(Heap &forward_heap, Heap &reverse_heap, const PhantomEndpoints &endpoints)
{
details::insertSourceInForwardHeap(forward_heap, endpoints.source_phantom);
details::insertTargetInReverseHeap(reverse_heap, endpoints.target_phantom);
}
template <typename Heap>
void insertNodesInHeaps(Heap &forward_heap,
Heap &reverse_heap,
const PhantomEndpointCandidates &endpoint_candidates)
{
for (const auto &source : endpoint_candidates.source_phantoms)
{
details::insertSourceInForwardHeap(forward_heap, source);
}
for (const auto &target : endpoint_candidates.target_phantoms)
{
details::insertTargetInReverseHeap(reverse_heap, target);
}
}
template <typename ManyToManyQueryHeap> template <typename ManyToManyQueryHeap>
void insertSourceInHeap(ManyToManyQueryHeap &heap, const PhantomNode &phantom_node) void insertSourceInHeap(ManyToManyQueryHeap &heap, const PhantomNodeCandidates &source_candidates)
{ {
for (const auto &phantom_node : source_candidates)
{
if (phantom_node.IsValidForwardSource()) if (phantom_node.IsValidForwardSource())
{ {
heap.Insert(phantom_node.forward_segment_id.id, heap.Insert(phantom_node.forward_segment_id.id,
@ -97,11 +140,14 @@ void insertSourceInHeap(ManyToManyQueryHeap &heap, const PhantomNode &phantom_no
-phantom_node.GetReverseDuration(), -phantom_node.GetReverseDuration(),
-phantom_node.GetReverseDistance()}); -phantom_node.GetReverseDistance()});
} }
}
} }
template <typename ManyToManyQueryHeap> template <typename ManyToManyQueryHeap>
void insertTargetInHeap(ManyToManyQueryHeap &heap, const PhantomNode &phantom_node) void insertTargetInHeap(ManyToManyQueryHeap &heap, const PhantomNodeCandidates &target_candidates)
{ {
for (const auto &phantom_node : target_candidates)
{
if (phantom_node.IsValidForwardTarget()) if (phantom_node.IsValidForwardTarget())
{ {
heap.Insert(phantom_node.forward_segment_id.id, heap.Insert(phantom_node.forward_segment_id.id,
@ -118,11 +164,12 @@ void insertTargetInHeap(ManyToManyQueryHeap &heap, const PhantomNode &phantom_no
phantom_node.GetReverseDuration(), phantom_node.GetReverseDuration(),
phantom_node.GetReverseDistance()}); phantom_node.GetReverseDistance()});
} }
}
} }
template <typename FacadeT> template <typename FacadeT>
void annotatePath(const FacadeT &facade, void annotatePath(const FacadeT &facade,
const PhantomNodes &phantom_node_pair, const PhantomEndpoints &endpoints,
const std::vector<NodeID> &unpacked_nodes, const std::vector<NodeID> &unpacked_nodes,
const std::vector<EdgeID> &unpacked_edges, const std::vector<EdgeID> &unpacked_edges,
std::vector<PathData> &unpacked_path) std::vector<PathData> &unpacked_path)
@ -133,14 +180,14 @@ void annotatePath(const FacadeT &facade,
const auto source_node_id = unpacked_nodes.front(); const auto source_node_id = unpacked_nodes.front();
const auto target_node_id = unpacked_nodes.back(); const auto target_node_id = unpacked_nodes.back();
const bool start_traversed_in_reverse = const bool start_traversed_in_reverse =
phantom_node_pair.source_phantom.forward_segment_id.id != source_node_id; endpoints.source_phantom.forward_segment_id.id != source_node_id;
const bool target_traversed_in_reverse = const bool target_traversed_in_reverse =
phantom_node_pair.target_phantom.forward_segment_id.id != target_node_id; endpoints.target_phantom.forward_segment_id.id != target_node_id;
BOOST_ASSERT(phantom_node_pair.source_phantom.forward_segment_id.id == source_node_id || BOOST_ASSERT(endpoints.source_phantom.forward_segment_id.id == source_node_id ||
phantom_node_pair.source_phantom.reverse_segment_id.id == source_node_id); endpoints.source_phantom.reverse_segment_id.id == source_node_id);
BOOST_ASSERT(phantom_node_pair.target_phantom.forward_segment_id.id == target_node_id || BOOST_ASSERT(endpoints.target_phantom.forward_segment_id.id == target_node_id ||
phantom_node_pair.target_phantom.reverse_segment_id.id == target_node_id); endpoints.target_phantom.reverse_segment_id.id == target_node_id);
// datastructures to hold extracted data from geometry // datastructures to hold extracted data from geometry
std::vector<NodeID> id_vector; std::vector<NodeID> id_vector;
@ -180,8 +227,8 @@ void annotatePath(const FacadeT &facade,
const auto geometry_index = facade.GetGeometryIndex(node_id); const auto geometry_index = facade.GetGeometryIndex(node_id);
get_segment_geometry(geometry_index); get_segment_geometry(geometry_index);
BOOST_ASSERT(id_vector.size() > 0); BOOST_ASSERT(!id_vector.empty());
BOOST_ASSERT(datasource_vector.size() > 0); BOOST_ASSERT(!datasource_vector.empty());
BOOST_ASSERT(weight_vector.size() + 1 == id_vector.size()); BOOST_ASSERT(weight_vector.size() + 1 == id_vector.size());
BOOST_ASSERT(duration_vector.size() + 1 == id_vector.size()); BOOST_ASSERT(duration_vector.size() + 1 == id_vector.size());
@ -190,11 +237,11 @@ void annotatePath(const FacadeT &facade,
std::size_t start_index = 0; std::size_t start_index = 0;
if (is_first_segment) if (is_first_segment)
{ {
unsigned short segment_position = phantom_node_pair.source_phantom.fwd_segment_position; unsigned short segment_position = endpoints.source_phantom.fwd_segment_position;
if (start_traversed_in_reverse) if (start_traversed_in_reverse)
{ {
segment_position = weight_vector.size() - segment_position =
phantom_node_pair.source_phantom.fwd_segment_position - 1; weight_vector.size() - endpoints.source_phantom.fwd_segment_position - 1;
} }
BOOST_ASSERT(segment_position >= 0); BOOST_ASSERT(segment_position >= 0);
start_index = static_cast<std::size_t>(segment_position); start_index = static_cast<std::size_t>(segment_position);
@ -214,7 +261,7 @@ void annotatePath(const FacadeT &facade,
datasource_vector[segment_idx], datasource_vector[segment_idx],
boost::none}); boost::none});
} }
BOOST_ASSERT(unpacked_path.size() > 0); BOOST_ASSERT(!unpacked_path.empty());
const auto turn_duration = facade.GetDurationPenaltyForEdgeID(turn_id); const auto turn_duration = facade.GetDurationPenaltyForEdgeID(turn_id);
const auto turn_weight = facade.GetWeightPenaltyForEdgeID(turn_id); const auto turn_weight = facade.GetWeightPenaltyForEdgeID(turn_id);
@ -237,19 +284,17 @@ void annotatePath(const FacadeT &facade,
{ {
if (is_local_path) if (is_local_path)
{ {
start_index = start_index = weight_vector.size() - endpoints.source_phantom.fwd_segment_position - 1;
weight_vector.size() - phantom_node_pair.source_phantom.fwd_segment_position - 1;
} }
end_index = end_index = weight_vector.size() - endpoints.target_phantom.fwd_segment_position - 1;
weight_vector.size() - phantom_node_pair.target_phantom.fwd_segment_position - 1;
} }
else else
{ {
if (is_local_path) if (is_local_path)
{ {
start_index = phantom_node_pair.source_phantom.fwd_segment_position; start_index = endpoints.source_phantom.fwd_segment_position;
} }
end_index = phantom_node_pair.target_phantom.fwd_segment_position; end_index = endpoints.target_phantom.fwd_segment_position;
} }
// Given the following compressed geometry: // Given the following compressed geometry:
@ -277,11 +322,11 @@ void annotatePath(const FacadeT &facade,
if (!unpacked_path.empty()) if (!unpacked_path.empty())
{ {
const auto source_weight = start_traversed_in_reverse const auto source_weight = start_traversed_in_reverse
? phantom_node_pair.source_phantom.reverse_weight ? endpoints.source_phantom.reverse_weight
: phantom_node_pair.source_phantom.forward_weight; : endpoints.source_phantom.forward_weight;
const auto source_duration = start_traversed_in_reverse const auto source_duration = start_traversed_in_reverse
? phantom_node_pair.source_phantom.reverse_duration ? endpoints.source_phantom.reverse_duration
: phantom_node_pair.source_phantom.forward_duration; : endpoints.source_phantom.forward_duration;
// The above code will create segments for (v, w), (w,x), (x, y) and (y, Z). // The above code will create segments for (v, w), (w,x), (x, y) and (y, Z).
// However the first segment duration needs to be adjusted to the fact that the source // However the first segment duration needs to be adjusted to the fact that the source
// phantom is in the middle of the segment. We do this by subtracting v--s from the // phantom is in the middle of the segment. We do this by subtracting v--s from the
@ -358,12 +403,11 @@ double getPathDistance(const DataFacade<Algorithm> &facade,
template <typename AlgorithmT> template <typename AlgorithmT>
InternalRouteResult extractRoute(const DataFacade<AlgorithmT> &facade, InternalRouteResult extractRoute(const DataFacade<AlgorithmT> &facade,
const EdgeWeight weight, const EdgeWeight weight,
const PhantomNodes &phantom_nodes, const PhantomEndpointCandidates &endpoint_candidates,
const std::vector<NodeID> &unpacked_nodes, const std::vector<NodeID> &unpacked_nodes,
const std::vector<EdgeID> &unpacked_edges) const std::vector<EdgeID> &unpacked_edges)
{ {
InternalRouteResult raw_route_data; InternalRouteResult raw_route_data;
raw_route_data.segment_end_coordinates = {phantom_nodes};
// No path found for both target nodes? // No path found for both target nodes?
if (INVALID_EDGE_WEIGHT == weight) if (INVALID_EDGE_WEIGHT == weight)
@ -371,15 +415,18 @@ InternalRouteResult extractRoute(const DataFacade<AlgorithmT> &facade,
return raw_route_data; return raw_route_data;
} }
auto phantom_endpoints = endpointsFromCandidates(endpoint_candidates, unpacked_nodes);
raw_route_data.leg_endpoints = {phantom_endpoints};
raw_route_data.shortest_path_weight = weight; raw_route_data.shortest_path_weight = weight;
raw_route_data.unpacked_path_segments.resize(1); raw_route_data.unpacked_path_segments.resize(1);
raw_route_data.source_traversed_in_reverse.push_back( raw_route_data.source_traversed_in_reverse.push_back(
(unpacked_nodes.front() != phantom_nodes.source_phantom.forward_segment_id.id)); (unpacked_nodes.front() != phantom_endpoints.source_phantom.forward_segment_id.id));
raw_route_data.target_traversed_in_reverse.push_back( raw_route_data.target_traversed_in_reverse.push_back(
(unpacked_nodes.back() != phantom_nodes.target_phantom.forward_segment_id.id)); (unpacked_nodes.back() != phantom_endpoints.target_phantom.forward_segment_id.id));
annotatePath(facade, annotatePath(facade,
phantom_nodes, phantom_endpoints,
unpacked_nodes, unpacked_nodes,
unpacked_edges, unpacked_edges,
raw_route_data.unpacked_path_segments.front()); raw_route_data.unpacked_path_segments.front());

View File

@ -120,8 +120,8 @@ void routingStep(const DataFacade<Algorithm> &facade,
NodeID &middle_node_id, NodeID &middle_node_id,
EdgeWeight &upper_bound, EdgeWeight &upper_bound,
EdgeWeight min_edge_offset, EdgeWeight min_edge_offset,
const bool force_loop_forward, const std::vector<NodeID> &force_loop_forward_nodes,
const bool force_loop_reverse) const std::vector<NodeID> &force_loop_reverse_nodes)
{ {
auto heapNode = forward_heap.DeleteMinGetHeapNode(); auto heapNode = forward_heap.DeleteMinGetHeapNode();
const auto reverseHeapNode = reverse_heap.GetHeapNodeIfWasInserted(heapNode.node); const auto reverseHeapNode = reverse_heap.GetHeapNodeIfWasInserted(heapNode.node);
@ -131,9 +131,8 @@ void routingStep(const DataFacade<Algorithm> &facade,
const EdgeWeight new_weight = reverseHeapNode->weight + heapNode.weight; const EdgeWeight new_weight = reverseHeapNode->weight + heapNode.weight;
if (new_weight < upper_bound) if (new_weight < upper_bound)
{ {
// if loops are forced, they are so at the source if (force_loop(force_loop_forward_nodes, heapNode) ||
if ((force_loop_forward && heapNode.data.parent == heapNode.node) || force_loop(force_loop_reverse_nodes, heapNode) ||
(force_loop_reverse && reverseHeapNode->data.parent == heapNode.node) ||
// in this case we are looking at a bi-directional way where the source // in this case we are looking at a bi-directional way where the source
// and target phantom are on the same edge based node // and target phantom are on the same edge based node
new_weight < 0) new_weight < 0)
@ -398,7 +397,7 @@ template <typename RandomIter, typename FacadeT>
void unpackPath(const FacadeT &facade, void unpackPath(const FacadeT &facade,
RandomIter packed_path_begin, RandomIter packed_path_begin,
RandomIter packed_path_end, RandomIter packed_path_end,
const PhantomNodes &phantom_nodes, const PhantomEndpoints &route_endpoints,
std::vector<PathData> &unpacked_path) std::vector<PathData> &unpacked_path)
{ {
const auto nodes_number = std::distance(packed_path_begin, packed_path_end); const auto nodes_number = std::distance(packed_path_begin, packed_path_end);
@ -422,7 +421,7 @@ void unpackPath(const FacadeT &facade,
}); });
} }
annotatePath(facade, phantom_nodes, unpacked_nodes, unpacked_edges, unpacked_path); annotatePath(facade, route_endpoints, unpacked_nodes, unpacked_edges, unpacked_path);
} }
/** /**
@ -467,12 +466,35 @@ void search(SearchEngineData<Algorithm> &engine_working_data,
const DataFacade<Algorithm> &facade, const DataFacade<Algorithm> &facade,
SearchEngineData<Algorithm>::QueryHeap &forward_heap, SearchEngineData<Algorithm>::QueryHeap &forward_heap,
SearchEngineData<Algorithm>::QueryHeap &reverse_heap, SearchEngineData<Algorithm>::QueryHeap &reverse_heap,
std::int32_t &weight, EdgeWeight &weight,
std::vector<NodeID> &packed_leg, std::vector<NodeID> &packed_leg,
const bool force_loop_forward, const std::vector<NodeID> &force_loop_forward_node,
const bool force_loop_reverse, const std::vector<NodeID> &force_loop_reverse_node,
const PhantomNodes &phantom_nodes, const EdgeWeight duration_upper_bound = INVALID_EDGE_WEIGHT);
const int duration_upper_bound = INVALID_EDGE_WEIGHT);
template <typename PhantomEndpointT>
void search(SearchEngineData<Algorithm> &engine_working_data,
const DataFacade<Algorithm> &facade,
SearchEngineData<Algorithm>::QueryHeap &forward_heap,
SearchEngineData<Algorithm>::QueryHeap &reverse_heap,
EdgeWeight &weight,
std::vector<NodeID> &packed_leg,
const std::vector<NodeID> &force_loop_forward_node,
const std::vector<NodeID> &force_loop_reverse_node,
const PhantomEndpointT & /*endpoints*/,
const EdgeWeight duration_upper_bound = INVALID_EDGE_WEIGHT)
{
// Avoid templating the CH search implementations.
return search(engine_working_data,
facade,
forward_heap,
reverse_heap,
weight,
packed_leg,
force_loop_forward_node,
force_loop_reverse_node,
duration_upper_bound);
}
// Requires the heaps for be empty // Requires the heaps for be empty
// If heaps should be adjusted to be initialized outside of this function, // If heaps should be adjusted to be initialized outside of this function,

View File

@ -33,24 +33,75 @@ namespace
template <typename MultiLevelPartition> template <typename MultiLevelPartition>
inline LevelID getNodeQueryLevel(const MultiLevelPartition &partition, inline LevelID getNodeQueryLevel(const MultiLevelPartition &partition,
NodeID node, NodeID node,
const PhantomNodes &phantom_nodes) const PhantomNode &source,
const PhantomNode &target)
{ {
auto level = [&partition, node](const SegmentID &source, const SegmentID &target) { auto level = [&partition, node](const SegmentID &source, const SegmentID &target) {
if (source.enabled && target.enabled) if (source.enabled && target.enabled)
return partition.GetQueryLevel(source.id, target.id, node); return partition.GetQueryLevel(source.id, target.id, node);
return INVALID_LEVEL_ID; return INVALID_LEVEL_ID;
}; };
return std::min(std::min(level(phantom_nodes.source_phantom.forward_segment_id,
phantom_nodes.target_phantom.forward_segment_id), return std::min(std::min(level(source.forward_segment_id, target.forward_segment_id),
level(phantom_nodes.source_phantom.forward_segment_id, level(source.forward_segment_id, target.reverse_segment_id)),
phantom_nodes.target_phantom.reverse_segment_id)), std::min(level(source.reverse_segment_id, target.forward_segment_id),
std::min(level(phantom_nodes.source_phantom.reverse_segment_id, level(source.reverse_segment_id, target.reverse_segment_id)));
phantom_nodes.target_phantom.forward_segment_id),
level(phantom_nodes.source_phantom.reverse_segment_id,
phantom_nodes.target_phantom.reverse_segment_id)));
} }
inline bool checkParentCellRestriction(CellID, const PhantomNodes &) { return true; } template <typename MultiLevelPartition>
inline LevelID getNodeQueryLevel(const MultiLevelPartition &partition,
NodeID node,
const PhantomEndpoints &endpoints)
{
return getNodeQueryLevel(partition, node, endpoints.source_phantom, endpoints.target_phantom);
}
template <typename MultiLevelPartition>
inline LevelID getNodeQueryLevel(const MultiLevelPartition &partition,
NodeID node,
const PhantomCandidatesToTarget &endpoint_candidates)
{
auto min_level = std::accumulate(
endpoint_candidates.source_phantoms.begin(),
endpoint_candidates.source_phantoms.end(),
INVALID_LEVEL_ID,
[&](LevelID current_level, const PhantomNode &source) {
return std::min(
current_level,
getNodeQueryLevel(partition, node, source, endpoint_candidates.target_phantom));
});
return min_level;
}
template <typename MultiLevelPartition>
inline LevelID getNodeQueryLevel(const MultiLevelPartition &partition,
NodeID node,
const PhantomEndpointCandidates &endpoint_candidates)
{
auto min_level = std::accumulate(
endpoint_candidates.source_phantoms.begin(),
endpoint_candidates.source_phantoms.end(),
INVALID_LEVEL_ID,
[&](LevelID level_1, const PhantomNode &source) {
return std::min(
level_1,
std::accumulate(endpoint_candidates.target_phantoms.begin(),
endpoint_candidates.target_phantoms.end(),
level_1,
[&](LevelID level_2, const PhantomNode &target) {
return std::min(
level_2,
getNodeQueryLevel(partition, node, source, target));
}));
});
return min_level;
}
template <typename PhantomCandidateT>
inline bool checkParentCellRestriction(CellID, const PhantomCandidateT &)
{
return true;
}
// Restricted search (Args is LevelID, CellID): // Restricted search (Args is LevelID, CellID):
// * use the fixed level for queries // * use the fixed level for queries
@ -72,17 +123,23 @@ inline bool checkParentCellRestriction(CellID cell, LevelID, CellID parent)
template <typename MultiLevelPartition> template <typename MultiLevelPartition>
inline LevelID getNodeQueryLevel(const MultiLevelPartition &partition, inline LevelID getNodeQueryLevel(const MultiLevelPartition &partition,
const NodeID node, const NodeID node,
const PhantomNode &phantom_node) const PhantomNodeCandidates &candidates)
{ {
auto highest_diffrent_level = [&partition, node](const SegmentID &phantom_node) { auto highest_different_level = [&partition, node](const SegmentID &segment) {
if (phantom_node.enabled) return segment.enabled ? partition.GetHighestDifferentLevel(segment.id, node)
return partition.GetHighestDifferentLevel(phantom_node.id, node); : INVALID_LEVEL_ID;
return INVALID_LEVEL_ID;
}; };
const auto node_level = std::min(highest_diffrent_level(phantom_node.forward_segment_id), auto node_level =
highest_diffrent_level(phantom_node.reverse_segment_id)); std::accumulate(candidates.begin(),
candidates.end(),
INVALID_LEVEL_ID,
[&](LevelID current_level, const PhantomNode &phantom_node) {
auto highest_level =
std::min(highest_different_level(phantom_node.forward_segment_id),
highest_different_level(phantom_node.reverse_segment_id));
return std::min(current_level, highest_level);
});
return node_level; return node_level;
} }
@ -92,31 +149,17 @@ inline LevelID getNodeQueryLevel(const MultiLevelPartition &partition,
template <typename MultiLevelPartition> template <typename MultiLevelPartition>
inline LevelID getNodeQueryLevel(const MultiLevelPartition &partition, inline LevelID getNodeQueryLevel(const MultiLevelPartition &partition,
NodeID node, NodeID node,
const std::vector<PhantomNode> &phantom_nodes, const std::vector<PhantomNodeCandidates> &candidates_list,
const std::size_t phantom_index, const std::size_t phantom_index,
const std::vector<std::size_t> &phantom_indices) const std::vector<std::size_t> &phantom_indices)
{ {
auto min_level = [&partition, node](const PhantomNode &phantom_node) {
const auto &forward_segment = phantom_node.forward_segment_id;
const auto forward_level =
forward_segment.enabled ? partition.GetHighestDifferentLevel(node, forward_segment.id)
: INVALID_LEVEL_ID;
const auto &reverse_segment = phantom_node.reverse_segment_id;
const auto reverse_level =
reverse_segment.enabled ? partition.GetHighestDifferentLevel(node, reverse_segment.id)
: INVALID_LEVEL_ID;
return std::min(forward_level, reverse_level);
};
// Get minimum level over all phantoms of the highest different level with respect to node // Get minimum level over all phantoms of the highest different level with respect to node
// This is equivalent to min_{∀ source, target} partition.GetQueryLevel(source, node, target) // This is equivalent to min_{∀ source, target} partition.GetQueryLevel(source, node, target)
auto result = min_level(phantom_nodes[phantom_index]); auto init = getNodeQueryLevel(partition, node, candidates_list[phantom_index]);
for (const auto &index : phantom_indices) auto result = std::accumulate(
{ phantom_indices.begin(), phantom_indices.end(), init, [&](LevelID level, size_t index) {
result = std::min(result, min_level(phantom_nodes[index])); return std::min(level, getNodeQueryLevel(partition, node, candidates_list[index]));
} });
return result; return result;
} }
} // namespace } // namespace
@ -229,7 +272,7 @@ template <bool DIRECTION, typename Algorithm, typename... Args>
void relaxOutgoingEdges(const DataFacade<Algorithm> &facade, void relaxOutgoingEdges(const DataFacade<Algorithm> &facade,
typename SearchEngineData<Algorithm>::QueryHeap &forward_heap, typename SearchEngineData<Algorithm>::QueryHeap &forward_heap,
const typename SearchEngineData<Algorithm>::QueryHeap::HeapNode &heapNode, const typename SearchEngineData<Algorithm>::QueryHeap::HeapNode &heapNode,
Args... args) const Args &... args)
{ {
const auto &partition = facade.GetMultiLevelPartition(); const auto &partition = facade.GetMultiLevelPartition();
const auto &cells = facade.GetCellStorage(); const auto &cells = facade.GetCellStorage();
@ -344,9 +387,9 @@ void routingStep(const DataFacade<Algorithm> &facade,
typename SearchEngineData<Algorithm>::QueryHeap &reverse_heap, typename SearchEngineData<Algorithm>::QueryHeap &reverse_heap,
NodeID &middle_node, NodeID &middle_node,
EdgeWeight &path_upper_bound, EdgeWeight &path_upper_bound,
const bool force_loop_forward, const std::vector<NodeID> &force_loop_forward_nodes,
const bool force_loop_reverse, const std::vector<NodeID> &force_loop_reverse_nodes,
Args... args) const Args &... args)
{ {
const auto heapNode = forward_heap.DeleteMinGetHeapNode(); const auto heapNode = forward_heap.DeleteMinGetHeapNode();
const auto weight = heapNode.weight; const auto weight = heapNode.weight;
@ -366,9 +409,9 @@ void routingStep(const DataFacade<Algorithm> &facade,
// MLD uses loops forcing only to prune single node paths in forward and/or // MLD uses loops forcing only to prune single node paths in forward and/or
// backward direction (there is no need to force loops in MLD but in CH) // backward direction (there is no need to force loops in MLD but in CH)
if (!(force_loop_forward && heapNode.data.parent == heapNode.node) && if (!force_loop(force_loop_forward_nodes, heapNode) &&
!(force_loop_reverse && reverseHeapNode->data.parent == heapNode.node) && !force_loop(force_loop_reverse_nodes, heapNode) && (path_weight >= 0) &&
(path_weight >= 0) && (path_weight < path_upper_bound)) (path_weight < path_upper_bound))
{ {
middle_node = heapNode.node; middle_node = heapNode.node;
path_upper_bound = path_weight; path_upper_bound = path_weight;
@ -393,10 +436,10 @@ UnpackedPath search(SearchEngineData<Algorithm> &engine_working_data,
const DataFacade<Algorithm> &facade, const DataFacade<Algorithm> &facade,
typename SearchEngineData<Algorithm>::QueryHeap &forward_heap, typename SearchEngineData<Algorithm>::QueryHeap &forward_heap,
typename SearchEngineData<Algorithm>::QueryHeap &reverse_heap, typename SearchEngineData<Algorithm>::QueryHeap &reverse_heap,
const bool force_loop_forward, const std::vector<NodeID> &force_loop_forward_nodes,
const bool force_loop_reverse, const std::vector<NodeID> &force_loop_reverse_nodes,
EdgeWeight weight_upper_bound, EdgeWeight weight_upper_bound,
Args... args) const Args &... args)
{ {
if (forward_heap.Empty() || reverse_heap.Empty()) if (forward_heap.Empty() || reverse_heap.Empty())
{ {
@ -423,8 +466,8 @@ UnpackedPath search(SearchEngineData<Algorithm> &engine_working_data,
reverse_heap, reverse_heap,
middle, middle,
weight, weight,
force_loop_forward, force_loop_forward_nodes,
force_loop_reverse, force_loop_reverse_nodes,
args...); args...);
if (!forward_heap.Empty()) if (!forward_heap.Empty())
forward_heap_min = forward_heap.MinKey(); forward_heap_min = forward_heap.MinKey();
@ -436,8 +479,8 @@ UnpackedPath search(SearchEngineData<Algorithm> &engine_working_data,
forward_heap, forward_heap,
middle, middle,
weight, weight,
force_loop_reverse, force_loop_reverse_nodes,
force_loop_forward, force_loop_forward_nodes,
args...); args...);
if (!reverse_heap.Empty()) if (!reverse_heap.Empty())
reverse_heap_min = reverse_heap.MinKey(); reverse_heap_min = reverse_heap.MinKey();
@ -494,12 +537,13 @@ UnpackedPath search(SearchEngineData<Algorithm> &engine_working_data,
EdgeWeight subpath_weight; EdgeWeight subpath_weight;
std::vector<NodeID> subpath_nodes; std::vector<NodeID> subpath_nodes;
std::vector<EdgeID> subpath_edges; std::vector<EdgeID> subpath_edges;
std::tie(subpath_weight, subpath_nodes, subpath_edges) = search(engine_working_data, std::tie(subpath_weight, subpath_nodes, subpath_edges) =
search(engine_working_data,
facade, facade,
forward_heap, forward_heap,
reverse_heap, reverse_heap,
force_loop_forward, force_loop_forward_nodes,
force_loop_reverse, force_loop_reverse_nodes,
INVALID_EDGE_WEIGHT, INVALID_EDGE_WEIGHT,
sublevel, sublevel,
parent_cell_id); parent_cell_id);
@ -517,16 +561,16 @@ UnpackedPath search(SearchEngineData<Algorithm> &engine_working_data,
} }
// Alias to be compatible with the CH-based search // Alias to be compatible with the CH-based search
template <typename Algorithm> template <typename Algorithm, typename PhantomEndpointT>
inline void search(SearchEngineData<Algorithm> &engine_working_data, inline void search(SearchEngineData<Algorithm> &engine_working_data,
const DataFacade<Algorithm> &facade, const DataFacade<Algorithm> &facade,
typename SearchEngineData<Algorithm>::QueryHeap &forward_heap, typename SearchEngineData<Algorithm>::QueryHeap &forward_heap,
typename SearchEngineData<Algorithm>::QueryHeap &reverse_heap, typename SearchEngineData<Algorithm>::QueryHeap &reverse_heap,
EdgeWeight &weight, EdgeWeight &weight,
std::vector<NodeID> &unpacked_nodes, std::vector<NodeID> &unpacked_nodes,
const bool force_loop_forward, const std::vector<NodeID> &force_loop_forward_node,
const bool force_loop_reverse, const std::vector<NodeID> &force_loop_reverse_node,
const PhantomNodes &phantom_nodes, const PhantomEndpointT &endpoints,
const EdgeWeight weight_upper_bound = INVALID_EDGE_WEIGHT) const EdgeWeight weight_upper_bound = INVALID_EDGE_WEIGHT)
{ {
// TODO: change search calling interface to use unpacked_edges result // TODO: change search calling interface to use unpacked_edges result
@ -534,10 +578,10 @@ inline void search(SearchEngineData<Algorithm> &engine_working_data,
facade, facade,
forward_heap, forward_heap,
reverse_heap, reverse_heap,
force_loop_forward, force_loop_forward_node,
force_loop_reverse, force_loop_reverse_node,
weight_upper_bound, weight_upper_bound,
phantom_nodes); endpoints);
} }
// TODO: refactor CH-related stub to use unpacked_edges // TODO: refactor CH-related stub to use unpacked_edges
@ -545,7 +589,7 @@ template <typename RandomIter, typename FacadeT>
void unpackPath(const FacadeT &facade, void unpackPath(const FacadeT &facade,
RandomIter packed_path_begin, RandomIter packed_path_begin,
RandomIter packed_path_end, RandomIter packed_path_end,
const PhantomNodes &phantom_nodes, const PhantomEndpoints &route_endpoints,
std::vector<PathData> &unpacked_path) std::vector<PathData> &unpacked_path)
{ {
const auto nodes_number = std::distance(packed_path_begin, packed_path_end); const auto nodes_number = std::distance(packed_path_begin, packed_path_end);
@ -568,7 +612,7 @@ void unpackPath(const FacadeT &facade,
}); });
} }
annotatePath(facade, phantom_nodes, unpacked_nodes, unpacked_edges, unpacked_path); annotatePath(facade, route_endpoints, unpacked_nodes, unpacked_edges, unpacked_path);
} }
template <typename Algorithm> template <typename Algorithm>
@ -583,8 +627,8 @@ double getNetworkDistance(SearchEngineData<Algorithm> &engine_working_data,
forward_heap.Clear(); forward_heap.Clear();
reverse_heap.Clear(); reverse_heap.Clear();
const PhantomNodes phantom_nodes{source_phantom, target_phantom}; const PhantomEndpoints endpoints{source_phantom, target_phantom};
insertNodesInHeaps(forward_heap, reverse_heap, phantom_nodes); insertNodesInHeaps(forward_heap, reverse_heap, endpoints);
EdgeWeight weight = INVALID_EDGE_WEIGHT; EdgeWeight weight = INVALID_EDGE_WEIGHT;
std::vector<NodeID> unpacked_nodes; std::vector<NodeID> unpacked_nodes;
@ -593,10 +637,10 @@ double getNetworkDistance(SearchEngineData<Algorithm> &engine_working_data,
facade, facade,
forward_heap, forward_heap,
reverse_heap, reverse_heap,
DO_NOT_FORCE_LOOPS, {},
DO_NOT_FORCE_LOOPS, {},
weight_upper_bound, weight_upper_bound,
phantom_nodes); endpoints);
if (weight == INVALID_EDGE_WEIGHT) if (weight == INVALID_EDGE_WEIGHT)
{ {
@ -605,7 +649,7 @@ double getNetworkDistance(SearchEngineData<Algorithm> &engine_working_data,
std::vector<PathData> unpacked_path; std::vector<PathData> unpacked_path;
annotatePath(facade, phantom_nodes, unpacked_nodes, unpacked_edges, unpacked_path); annotatePath(facade, endpoints, unpacked_nodes, unpacked_edges, unpacked_path);
return getPathDistance(facade, unpacked_path, source_phantom, target_phantom); return getPathDistance(facade, unpacked_path, source_phantom, target_phantom);
} }

View File

@ -14,9 +14,10 @@ namespace routing_algorithms
{ {
template <typename Algorithm> template <typename Algorithm>
InternalRouteResult shortestPathSearch(SearchEngineData<Algorithm> &engine_working_data, InternalRouteResult
shortestPathSearch(SearchEngineData<Algorithm> &engine_working_data,
const DataFacade<Algorithm> &facade, const DataFacade<Algorithm> &facade,
const std::vector<PhantomNodes> &phantom_nodes_vector, const std::vector<PhantomNodeCandidates> &waypoint_candidates,
const boost::optional<bool> continue_straight_at_waypoint); const boost::optional<bool> continue_straight_at_waypoint);
} // namespace routing_algorithms } // namespace routing_algorithms

File diff suppressed because it is too large Load Diff

View File

@ -78,10 +78,17 @@ struct BaseParametersGrammar : boost::spirit::qi::grammar<Iterator, Signature>
: BaseParametersGrammar::base_type(root_rule) : BaseParametersGrammar::base_type(root_rule)
{ {
const auto add_hint = [](engine::api::BaseParameters &base_parameters, const auto add_hint = [](engine::api::BaseParameters &base_parameters,
const boost::optional<std::string> &hint_string) { const std::vector<std::string> &hint_strings) {
if (hint_string) if (!hint_strings.empty())
{ {
base_parameters.hints.emplace_back(engine::Hint::FromBase64(hint_string.get())); std::vector<engine::SegmentHint> location_hints(hint_strings.size());
std::transform(hint_strings.begin(),
hint_strings.end(),
location_hints.begin(),
[](const auto &hint_string) {
return engine::SegmentHint::FromBase64(hint_string);
});
base_parameters.hints.push_back(engine::Hint{std::move(location_hints)});
} }
else else
{ {
@ -145,8 +152,9 @@ struct BaseParametersGrammar : boost::spirit::qi::grammar<Iterator, Signature>
(-(qi::double_ | unlimited_rule) % (-(qi::double_ | unlimited_rule) %
';')[ph::bind(&engine::api::BaseParameters::radiuses, qi::_r1) = qi::_1]; ';')[ph::bind(&engine::api::BaseParameters::radiuses, qi::_r1) = qi::_1];
hints_rule = qi::lit("hints=") > hints_rule =
(-qi::as_string[qi::repeat(engine::ENCODED_HINT_SIZE)[base64_char]])[ph::bind( qi::lit("hints=") >
(*qi::as_string[qi::repeat(engine::ENCODED_SEGMENT_HINT_SIZE)[base64_char]])[ph::bind(
add_hint, qi::_r1, qi::_1)] % add_hint, qi::_r1, qi::_1)] %
';'; ';';

View File

@ -68,7 +68,7 @@ write(storage::tar::FileWriter &writer,
/*** /***
* Static RTree for serving nearest neighbour queries * Static RTree for serving nearest neighbour queries
* // All coordinates are pojected first to Web Mercator before the bounding boxes * // All coordinates are projected first to Web Mercator before the bounding boxes
* // are computed, this means the internal distance metric doesn not represent meters! * // are computed, this means the internal distance metric doesn not represent meters!
*/ */
@ -556,7 +556,7 @@ class StaticRTree
} }
// Override filter and terminator for the desired behaviour. // Override filter and terminator for the desired behaviour.
std::vector<EdgeDataT> Nearest(const Coordinate input_coordinate, std::vector<CandidateSegment> Nearest(const Coordinate input_coordinate,
const std::size_t max_results) const const std::size_t max_results) const
{ {
return Nearest( return Nearest(
@ -567,13 +567,13 @@ class StaticRTree
}); });
} }
// Override filter and terminator for the desired behaviour. // Return edges in distance order with the coordinate of the closest point on the edge.
template <typename FilterT, typename TerminationT> template <typename FilterT, typename TerminationT>
std::vector<EdgeDataT> Nearest(const Coordinate input_coordinate, std::vector<CandidateSegment> Nearest(const Coordinate input_coordinate,
const FilterT filter, const FilterT filter,
const TerminationT terminate) const const TerminationT terminate) const
{ {
std::vector<EdgeDataT> results; std::vector<CandidateSegment> results;
auto projected_coordinate = web_mercator::fromWGS84(input_coordinate); auto projected_coordinate = web_mercator::fromWGS84(input_coordinate);
Coordinate fixed_projected_coordinate{projected_coordinate}; Coordinate fixed_projected_coordinate{projected_coordinate};
// initialize queue with root element // initialize queue with root element
@ -603,10 +603,10 @@ class StaticRTree
} }
else else
{ // current candidate is an actual road segment { // current candidate is an actual road segment
// We deliberatly make a copy here, we mutate the value below const auto &edge_data = m_objects[current_query_node.segment_index];
auto edge_data = m_objects[current_query_node.segment_index]; // We deliberately make an edge data copy here, we mutate the value below
const auto &current_candidate = CandidateSegment current_candidate{current_query_node.fixed_projected_coordinate,
CandidateSegment{current_query_node.fixed_projected_coordinate, edge_data}; edge_data};
// to allow returns of no-results if too restrictive filtering, this needs to be // to allow returns of no-results if too restrictive filtering, this needs to be
// done here even though performance would indicate that we want to stop after // done here even though performance would indicate that we want to stop after
@ -621,11 +621,11 @@ class StaticRTree
{ {
continue; continue;
} }
edge_data.forward_segment_id.enabled &= use_segment.first; current_candidate.data.forward_segment_id.enabled &= use_segment.first;
edge_data.reverse_segment_id.enabled &= use_segment.second; current_candidate.data.reverse_segment_id.enabled &= use_segment.second;
// store phantom node in result vector // store phantom node in result vector
results.push_back(std::move(edge_data)); results.push_back(std::move(current_candidate));
} }
} }
@ -676,7 +676,7 @@ class StaticRTree
* Iterates over all the children of a TreeNode and inserts them into the search * Iterates over all the children of a TreeNode and inserts them into the search
* priority queue using their distance from the search coordinate as the * priority queue using their distance from the search coordinate as the
* priority metric. * priority metric.
* The closests distance to a box from our point is also the closest distance * The closest distance to a box from our point is also the closest distance
* to the closest line in that box (assuming the boxes hug their contents). * to the closest line in that box (assuming the boxes hug their contents).
*/ */
template <class QueueT> template <class QueueT>

View File

@ -239,10 +239,10 @@ makeWaypoint(const util::Coordinate &location, const double &distance, std::stri
util::json::Object makeWaypoint(const util::Coordinate &location, util::json::Object makeWaypoint(const util::Coordinate &location,
const double &distance, const double &distance,
std::string name, std::string name,
const Hint &hint) const Hint &location_hints)
{ {
auto waypoint = makeWaypoint(location, distance, std::move(name)); auto waypoint = makeWaypoint(location, distance, std::move(name));
waypoint.values["hint"] = hint.ToBase64(); waypoint.values["hint"] = location_hints.ToBase64();
return waypoint; return waypoint;
} }

View File

@ -3,10 +3,10 @@
#include "engine/datafacade/datafacade_base.hpp" #include "engine/datafacade/datafacade_base.hpp"
#include <boost/assert.hpp> #include <boost/assert.hpp>
#include <boost/unordered_set.hpp>
#include <algorithm> #include <algorithm>
#include <iterator> #include <iterator>
#include <ostream>
#include <tuple> #include <tuple>
namespace osrm namespace osrm
@ -14,7 +14,7 @@ namespace osrm
namespace engine namespace engine
{ {
bool Hint::IsValid(const util::Coordinate new_input_coordinates, bool SegmentHint::IsValid(const util::Coordinate new_input_coordinates,
const datafacade::BaseDataFacade &facade) const const datafacade::BaseDataFacade &facade) const
{ {
auto is_same_input_coordinate = new_input_coordinates.lon == phantom.input_location.lon && auto is_same_input_coordinate = new_input_coordinates.lon == phantom.input_location.lon &&
@ -25,7 +25,7 @@ bool Hint::IsValid(const util::Coordinate new_input_coordinates,
return is_same_input_coordinate && phantom.IsValid() && facade.GetCheckSum() == data_checksum; return is_same_input_coordinate && phantom.IsValid() && facade.GetCheckSum() == data_checksum;
} }
std::string Hint::ToBase64() const std::string SegmentHint::ToBase64() const
{ {
auto base64 = encodeBase64Bytewise(*this); auto base64 = encodeBase64Bytewise(*this);
@ -36,9 +36,9 @@ std::string Hint::ToBase64() const
return base64; return base64;
} }
Hint Hint::FromBase64(const std::string &base64Hint) SegmentHint SegmentHint::FromBase64(const std::string &base64Hint)
{ {
BOOST_ASSERT_MSG(base64Hint.size() == ENCODED_HINT_SIZE, "Hint has invalid size"); BOOST_ASSERT_MSG(base64Hint.size() == ENCODED_SEGMENT_HINT_SIZE, "Hint has invalid size");
// We need mutability but don't want to change the API // We need mutability but don't want to change the API
auto encoded = base64Hint; auto encoded = base64Hint;
@ -47,15 +47,82 @@ Hint Hint::FromBase64(const std::string &base64Hint)
std::replace(begin(encoded), end(encoded), '-', '+'); std::replace(begin(encoded), end(encoded), '-', '+');
std::replace(begin(encoded), end(encoded), '_', '/'); std::replace(begin(encoded), end(encoded), '_', '/');
return decodeBase64Bytewise<Hint>(encoded); return decodeBase64Bytewise<SegmentHint>(encoded);
} }
bool operator==(const Hint &lhs, const Hint &rhs) bool operator==(const SegmentHint &lhs, const SegmentHint &rhs)
{ {
return std::tie(lhs.phantom, lhs.data_checksum) == std::tie(rhs.phantom, rhs.data_checksum); return std::tie(lhs.phantom, lhs.data_checksum) == std::tie(rhs.phantom, rhs.data_checksum);
} }
std::ostream &operator<<(std::ostream &out, const Hint &hint) { return out << hint.ToBase64(); } bool operator!=(const SegmentHint &lhs, const SegmentHint &rhs) { return !(lhs == rhs); }
std::ostream &operator<<(std::ostream &out, const SegmentHint &hint)
{
return out << hint.ToBase64();
}
std::string Hint::ToBase64() const
{
std::string res;
for (const auto &hint : segment_hints)
{
res += hint.ToBase64();
}
return res;
}
Hint Hint::FromBase64(const std::string &base64Hint)
{
BOOST_ASSERT_MSG(base64Hint.size() % ENCODED_SEGMENT_HINT_SIZE == 0,
"SegmentHint has invalid size");
auto num_hints = base64Hint.size() / ENCODED_SEGMENT_HINT_SIZE;
std::vector<SegmentHint> res(num_hints);
for (const auto i : util::irange<std::size_t>(0UL, num_hints))
{
auto start_offset = i * ENCODED_SEGMENT_HINT_SIZE;
auto end_offset = start_offset + ENCODED_SEGMENT_HINT_SIZE;
res[i] = SegmentHint::FromBase64(
std::string(base64Hint.begin() + start_offset, base64Hint.begin() + end_offset));
}
return {std::move(res)};
}
bool Hint::IsValid(const util::Coordinate new_input_coordinates,
const datafacade::BaseDataFacade &facade) const
{
const auto all_valid =
std::all_of(segment_hints.begin(), segment_hints.end(), [&](const auto &seg_hint) {
return seg_hint.IsValid(new_input_coordinates, facade);
});
if (!all_valid)
{
return false;
}
// Check hints do not contain duplicate segment pairs
// We can't allow duplicates as search heaps do not support it.
boost::unordered_set<NodeID> forward_segments;
boost::unordered_set<NodeID> reverse_segments;
for (const auto &seg_hint : segment_hints)
{
const auto forward_res = forward_segments.insert(seg_hint.phantom.forward_segment_id.id);
if (!forward_res.second)
{
return false;
}
const auto backward_res = reverse_segments.insert(seg_hint.phantom.reverse_segment_id.id);
if (!backward_res.second)
{
return false;
}
}
return true;
}
} // namespace engine } // namespace engine
} // namespace osrm } // namespace osrm

View File

@ -4,21 +4,16 @@
#include "engine/api/match_api.hpp" #include "engine/api/match_api.hpp"
#include "engine/api/match_parameters.hpp" #include "engine/api/match_parameters.hpp"
#include "engine/api/match_parameters_tidy.hpp" #include "engine/api/match_parameters_tidy.hpp"
#include "engine/map_matching/bayes_classifier.hpp"
#include "engine/map_matching/sub_matching.hpp" #include "engine/map_matching/sub_matching.hpp"
#include "util/coordinate_calculation.hpp" #include "util/coordinate_calculation.hpp"
#include "util/integer_range.hpp" #include "util/integer_range.hpp"
#include "util/json_util.hpp"
#include "util/string_util.hpp"
#include <cstdlib> #include <cstdlib>
#include <algorithm> #include <algorithm>
#include <functional> #include <functional>
#include <iterator>
#include <memory> #include <memory>
#include <set> #include <set>
#include <string>
#include <vector> #include <vector>
namespace osrm namespace osrm
@ -28,7 +23,7 @@ namespace engine
namespace plugins namespace plugins
{ {
// Filters PhantomNodes to obtain a set of viable candiates // Filters PhantomNodes to obtain a set of viable candidates
void filterCandidates(const std::vector<util::Coordinate> &coordinates, void filterCandidates(const std::vector<util::Coordinate> &coordinates,
MatchPlugin::CandidateLists &candidates_lists) MatchPlugin::CandidateLists &candidates_lists)
{ {
@ -272,20 +267,26 @@ Status MatchPlugin::HandleRequest(const RoutingAlgorithmsInterface &algorithms,
// FIXME we only run this to obtain the geometry // FIXME we only run this to obtain the geometry
// The clean way would be to get this directly from the map matching plugin // The clean way would be to get this directly from the map matching plugin
PhantomNodes current_phantom_node_pair;
for (unsigned i = 0; i < sub_matchings[index].nodes.size() - 1; ++i) for (unsigned i = 0; i < sub_matchings[index].nodes.size() - 1; ++i)
{ {
current_phantom_node_pair.source_phantom = sub_matchings[index].nodes[i]; PhantomEndpoints current_endpoints{sub_matchings[index].nodes[i],
current_phantom_node_pair.target_phantom = sub_matchings[index].nodes[i + 1]; sub_matchings[index].nodes[i + 1]};
BOOST_ASSERT(current_phantom_node_pair.source_phantom.IsValid()); BOOST_ASSERT(current_endpoints.source_phantom.IsValid());
BOOST_ASSERT(current_phantom_node_pair.target_phantom.IsValid()); BOOST_ASSERT(current_endpoints.target_phantom.IsValid());
sub_routes[index].segment_end_coordinates.emplace_back(current_phantom_node_pair); sub_routes[index].leg_endpoints.push_back(current_endpoints);
} }
std::vector<PhantomNodeCandidates> waypoint_candidates;
waypoint_candidates.reserve(sub_matchings[index].nodes.size());
std::transform(sub_matchings[index].nodes.begin(),
sub_matchings[index].nodes.end(),
std::back_inserter(waypoint_candidates),
[](const auto &phantom) { return PhantomNodeCandidates{phantom}; });
// force uturns to be on // force uturns to be on
// we split the phantom nodes anyway and only have bi-directional phantom nodes for // we split the phantom nodes anyway and only have bi-directional phantom nodes for
// possible uturns // possible uturns
sub_routes[index] = sub_routes[index] = algorithms.ShortestPathSearch(waypoint_candidates, {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) if (collapse_legs)
{ {

View File

@ -1,10 +1,7 @@
#include "engine/plugins/nearest.hpp" #include "engine/plugins/nearest.hpp"
#include "engine/api/nearest_api.hpp" #include "engine/api/nearest_api.hpp"
#include "engine/api/nearest_parameters.hpp" #include "engine/api/nearest_parameters.hpp"
#include "engine/phantom_node.hpp"
#include "util/integer_range.hpp"
#include <cstddef>
#include <string> #include <string>
#include <boost/assert.hpp> #include <boost/assert.hpp>

View File

@ -2,17 +2,11 @@
#include "engine/api/table_api.hpp" #include "engine/api/table_api.hpp"
#include "engine/api/table_parameters.hpp" #include "engine/api/table_parameters.hpp"
#include "engine/routing_algorithms/many_to_many.hpp"
#include "engine/search_engine_data.hpp"
#include "util/coordinate_calculation.hpp" #include "util/coordinate_calculation.hpp"
#include "util/json_container.hpp"
#include "util/string_util.hpp" #include "util/string_util.hpp"
#include <cstdlib> #include <cstdlib>
#include <algorithm>
#include <memory>
#include <string>
#include <vector> #include <vector>
#include <boost/assert.hpp> #include <boost/assert.hpp>
@ -47,7 +41,7 @@ Status TablePlugin::HandleRequest(const RoutingAlgorithmsInterface &algorithms,
return Error("InvalidOptions", "Coordinates are invalid", result); return Error("InvalidOptions", "Coordinates are invalid", result);
} }
if (params.bearings.size() > 0 && params.coordinates.size() != params.bearings.size()) if (!params.bearings.empty() && params.coordinates.size() != params.bearings.size())
{ {
return Error( return Error(
"InvalidOptions", "Number of bearings does not match number of coordinates", result); "InvalidOptions", "Number of bearings does not match number of coordinates", result);
@ -79,7 +73,7 @@ Status TablePlugin::HandleRequest(const RoutingAlgorithmsInterface &algorithms,
"NoSegment", MissingPhantomErrorMessage(phantom_nodes, params.coordinates), result); "NoSegment", MissingPhantomErrorMessage(phantom_nodes, params.coordinates), result);
} }
auto snapped_phantoms = SnapPhantomNodes(phantom_nodes); auto snapped_phantoms = SnapPhantomNodes(std::move(phantom_nodes));
bool request_distance = params.annotations & api::TableParameters::AnnotationsType::Distance; bool request_distance = params.annotations & api::TableParameters::AnnotationsType::Distance;
bool request_duration = params.annotations & api::TableParameters::AnnotationsType::Duration; bool request_duration = params.annotations & api::TableParameters::AnnotationsType::Duration;
@ -117,9 +111,11 @@ Status TablePlugin::HandleRequest(const RoutingAlgorithmsInterface &algorithms,
params.fallback_coordinate_type == params.fallback_coordinate_type ==
api::TableParameters::FallbackCoordinateType::Input api::TableParameters::FallbackCoordinateType::Input
? util::coordinate_calculation::greatCircleDistance( ? util::coordinate_calculation::greatCircleDistance(
source.input_location, destination.input_location) candidatesInputLocation(source),
candidatesInputLocation(destination))
: util::coordinate_calculation::greatCircleDistance( : util::coordinate_calculation::greatCircleDistance(
source.location, destination.location); candidatesSnappedLocation(source),
candidatesSnappedLocation(destination));
result_tables_pair.first[table_index] = result_tables_pair.first[table_index] =
distance_estimate / (double)params.fallback_speed; distance_estimate / (double)params.fallback_speed;

View File

@ -20,7 +20,6 @@
#include <algorithm> #include <algorithm>
#include <numeric> #include <numeric>
#include <string> #include <string>
#include <unordered_map>
#include <utility> #include <utility>
#include <vector> #include <vector>

View File

@ -4,18 +4,12 @@
#include "engine/api/trip_parameters.hpp" #include "engine/api/trip_parameters.hpp"
#include "engine/trip/trip_brute_force.hpp" #include "engine/trip/trip_brute_force.hpp"
#include "engine/trip/trip_farthest_insertion.hpp" #include "engine/trip/trip_farthest_insertion.hpp"
#include "engine/trip/trip_nearest_neighbour.hpp"
#include "util/dist_table_wrapper.hpp" // to access the dist table more easily #include "util/dist_table_wrapper.hpp" // to access the dist table more easily
#include "util/json_container.hpp"
#include <boost/assert.hpp> #include <boost/assert.hpp>
#include <algorithm> #include <algorithm>
#include <cstdlib>
#include <iterator>
#include <limits> #include <limits>
#include <memory>
#include <string>
#include <utility> #include <utility>
#include <vector> #include <vector>
@ -41,40 +35,33 @@ bool IsSupportedParameterCombination(const bool fixed_start,
// given the node order in which to visit, compute the actual route (with geometry, travel time and // given the node order in which to visit, compute the actual route (with geometry, travel time and
// so on) and return the result // so on) and return the result
InternalRouteResult TripPlugin::ComputeRoute(const RoutingAlgorithmsInterface &algorithms, InternalRouteResult
const std::vector<PhantomNode> &snapped_phantoms, TripPlugin::ComputeRoute(const RoutingAlgorithmsInterface &algorithms,
const std::vector<PhantomNodeCandidates> &waypoint_candidates,
const std::vector<NodeID> &trip, const std::vector<NodeID> &trip,
const bool roundtrip) const const bool roundtrip) const
{ {
InternalRouteResult min_route;
// given the final trip, compute total duration and return the route and location permutation
PhantomNodes viapoint;
// computes a roundtrip from the nodes in trip
for (auto node = trip.begin(); node < trip.end() - 1; ++node)
{
const auto from_node = *node;
const auto to_node = *std::next(node);
viapoint = PhantomNodes{snapped_phantoms[from_node], snapped_phantoms[to_node]};
min_route.segment_end_coordinates.emplace_back(viapoint);
}
// TODO make a more efficient solution that doesn't require copying all the waypoints vectors.
std::vector<PhantomNodeCandidates> trip_candidates;
std::transform(trip.begin(),
trip.end(),
std::back_inserter(trip_candidates),
[&](const auto &node) { return waypoint_candidates[node]; });
// return back to the first node if it is a round trip // return back to the first node if it is a round trip
if (roundtrip) if (roundtrip)
{ {
viapoint = PhantomNodes{snapped_phantoms[trip.back()], snapped_phantoms[trip.front()]}; trip_candidates.push_back(waypoint_candidates[trip.front()]);
min_route.segment_end_coordinates.emplace_back(viapoint);
// trip comes out to be something like 0 1 4 3 2 0 // trip comes out to be something like 0 1 4 3 2 0
BOOST_ASSERT(min_route.segment_end_coordinates.size() == trip.size()); BOOST_ASSERT(trip_candidates.size() == trip.size() + 1);
} }
else else
{ {
// trip comes out to be something like 0 1 4 3 2, so the sizes don't match // trip comes out to be something like 0 1 4 3 2
BOOST_ASSERT(min_route.segment_end_coordinates.size() == trip.size() - 1); BOOST_ASSERT(trip_candidates.size() == trip.size());
} }
min_route = algorithms.ShortestPathSearch(min_route.segment_end_coordinates, {false}); auto min_route = algorithms.ShortestPathSearch(trip_candidates, {false});
BOOST_ASSERT_MSG(min_route.shortest_path_weight < INVALID_EDGE_WEIGHT, "unroutable route"); BOOST_ASSERT_MSG(min_route.shortest_path_weight < INVALID_EDGE_WEIGHT, "unroutable route");
return min_route; return min_route;
} }
@ -226,7 +213,7 @@ Status TripPlugin::HandleRequest(const RoutingAlgorithmsInterface &algorithms,
return Error("InvalidValue", "Invalid source or destination value.", result); return Error("InvalidValue", "Invalid source or destination value.", result);
} }
auto snapped_phantoms = SnapPhantomNodes(phantom_node_pairs); auto snapped_phantoms = SnapPhantomNodes(std::move(phantom_node_pairs));
BOOST_ASSERT(snapped_phantoms.size() == number_of_locations); BOOST_ASSERT(snapped_phantoms.size() == number_of_locations);

View File

@ -5,12 +5,10 @@
#include "util/for_each_pair.hpp" #include "util/for_each_pair.hpp"
#include "util/integer_range.hpp" #include "util/integer_range.hpp"
#include "util/json_container.hpp"
#include <cstdlib> #include <cstdlib>
#include <algorithm> #include <algorithm>
#include <memory>
#include <string> #include <string>
#include <vector> #include <vector>
@ -95,19 +93,10 @@ Status ViaRoutePlugin::HandleRequest(const RoutingAlgorithmsInterface &algorithm
} }
BOOST_ASSERT(phantom_node_pairs.size() == route_parameters.coordinates.size()); BOOST_ASSERT(phantom_node_pairs.size() == route_parameters.coordinates.size());
auto snapped_phantoms = SnapPhantomNodes(phantom_node_pairs); auto snapped_phantoms = SnapPhantomNodes(std::move(phantom_node_pairs));
std::vector<PhantomNodes> start_end_nodes;
auto build_phantom_pairs = [&start_end_nodes](const PhantomNode &first_node,
const PhantomNode &second_node) {
start_end_nodes.push_back(PhantomNodes{first_node, second_node});
};
util::for_each_pair(snapped_phantoms, build_phantom_pairs);
api::RouteAPI route_api{facade, route_parameters}; api::RouteAPI route_api{facade, route_parameters};
InternalManyRoutesResult routes;
// TODO: in v6 we should remove the boolean and only keep the number parameter. // TODO: in v6 we should remove the boolean and only keep the number parameter.
// For now just force them to be in sync. and keep backwards compatibility. // For now just force them to be in sync. and keep backwards compatibility.
const auto wants_alternatives = const auto wants_alternatives =
@ -115,20 +104,23 @@ Status ViaRoutePlugin::HandleRequest(const RoutingAlgorithmsInterface &algorithm
(route_parameters.alternatives || route_parameters.number_of_alternatives > 0); (route_parameters.alternatives || route_parameters.number_of_alternatives > 0);
const auto number_of_alternatives = std::max(1u, route_parameters.number_of_alternatives); const auto number_of_alternatives = std::max(1u, route_parameters.number_of_alternatives);
InternalManyRoutesResult routes;
// Alternatives do not support vias, only direct s,t queries supported // Alternatives do not support vias, only direct s,t queries supported
// See the implementation notes and high-level outline. // See the implementation notes and high-level outline.
// https://github.com/Project-OSRM/osrm-backend/issues/3905 // https://github.com/Project-OSRM/osrm-backend/issues/3905
if (1 == start_end_nodes.size() && algorithms.HasAlternativePathSearch() && wants_alternatives) if (2 == snapped_phantoms.size() && algorithms.HasAlternativePathSearch() && wants_alternatives)
{ {
routes = algorithms.AlternativePathSearch(start_end_nodes.front(), number_of_alternatives); routes = algorithms.AlternativePathSearch({snapped_phantoms[0], snapped_phantoms[1]},
number_of_alternatives);
} }
else if (1 == start_end_nodes.size() && algorithms.HasDirectShortestPathSearch()) else if (2 == snapped_phantoms.size() && algorithms.HasDirectShortestPathSearch())
{ {
routes = algorithms.DirectShortestPathSearch(start_end_nodes.front()); routes = algorithms.DirectShortestPathSearch({snapped_phantoms[0], snapped_phantoms[1]});
} }
else else
{ {
routes = algorithms.ShortestPathSearch(start_end_nodes, route_parameters.continue_straight); routes =
algorithms.ShortestPathSearch(snapped_phantoms, route_parameters.continue_straight);
} }
// The post condition for all path searches is we have at least one route in our result. // The post condition for all path searches is we have at least one route in our result.
@ -160,18 +152,29 @@ Status ViaRoutePlugin::HandleRequest(const RoutingAlgorithmsInterface &algorithm
} }
} }
route_api.MakeResponse(routes, start_end_nodes, result); route_api.MakeResponse(routes, snapped_phantoms, result);
} }
else else
{ {
auto first_component_id = snapped_phantoms.front().component.id; const auto all_in_same_component =
auto not_in_same_component = std::any_of(snapped_phantoms.begin(), [](const std::vector<PhantomNodeCandidates> &waypoint_candidates) {
snapped_phantoms.end(), return std::any_of(waypoint_candidates.front().begin(),
[first_component_id](const PhantomNode &node) { waypoint_candidates.front().end(),
return node.component.id != first_component_id; // For each of the first possible phantoms, check if all other
// positions in the list have a phantom from the same component.
[&](const PhantomNode &phantom) {
const auto component_id = phantom.component.id;
return std::all_of(
std::next(waypoint_candidates.begin()),
std::end(waypoint_candidates),
[component_id](const PhantomNodeCandidates &candidates) {
return candidatesHaveComponent(candidates,
component_id);
}); });
});
};
if (not_in_same_component) if (!all_in_same_component(snapped_phantoms))
{ {
return Error("NoRoute", "Impossible route between points", result); return Error("NoRoute", "Impossible route between points", result);
} }

View File

@ -190,8 +190,8 @@ void computeWeightAndSharingOfViaPath(SearchEngineData<Algorithm> &engine_workin
s_v_middle, s_v_middle,
upper_bound_s_v_path_weight, upper_bound_s_v_path_weight,
min_edge_offset, min_edge_offset,
DO_NOT_FORCE_LOOPS, {},
DO_NOT_FORCE_LOOPS); {});
} }
// compute path <v,..,t> by reusing backward search from node t // compute path <v,..,t> by reusing backward search from node t
NodeID v_t_middle = SPECIAL_NODEID; NodeID v_t_middle = SPECIAL_NODEID;
@ -205,8 +205,8 @@ void computeWeightAndSharingOfViaPath(SearchEngineData<Algorithm> &engine_workin
v_t_middle, v_t_middle,
upper_bound_of_v_t_path_weight, upper_bound_of_v_t_path_weight,
min_edge_offset, min_edge_offset,
DO_NOT_FORCE_LOOPS, {},
DO_NOT_FORCE_LOOPS); {});
} }
*real_weight_of_via_path = upper_bound_s_v_path_weight + upper_bound_of_v_t_path_weight; *real_weight_of_via_path = upper_bound_s_v_path_weight + upper_bound_of_v_t_path_weight;
@ -351,8 +351,8 @@ bool viaNodeCandidatePassesTTest(SearchEngineData<Algorithm> &engine_working_dat
*s_v_middle, *s_v_middle,
upper_bound_s_v_path_weight, upper_bound_s_v_path_weight,
min_edge_offset, min_edge_offset,
DO_NOT_FORCE_LOOPS, {},
DO_NOT_FORCE_LOOPS); {});
} }
if (INVALID_EDGE_WEIGHT == upper_bound_s_v_path_weight) if (INVALID_EDGE_WEIGHT == upper_bound_s_v_path_weight)
@ -372,8 +372,8 @@ bool viaNodeCandidatePassesTTest(SearchEngineData<Algorithm> &engine_working_dat
*v_t_middle, *v_t_middle,
upper_bound_of_v_t_path_weight, upper_bound_of_v_t_path_weight,
min_edge_offset, min_edge_offset,
DO_NOT_FORCE_LOOPS, {},
DO_NOT_FORCE_LOOPS); {});
} }
if (INVALID_EDGE_WEIGHT == upper_bound_of_v_t_path_weight) if (INVALID_EDGE_WEIGHT == upper_bound_of_v_t_path_weight)
@ -539,25 +539,13 @@ bool viaNodeCandidatePassesTTest(SearchEngineData<Algorithm> &engine_working_dat
{ {
if (!forward_heap3.Empty()) if (!forward_heap3.Empty())
{ {
routingStep<FORWARD_DIRECTION>(facade, routingStep<FORWARD_DIRECTION>(
forward_heap3, facade, forward_heap3, reverse_heap3, middle, upper_bound, min_edge_offset, {}, {});
reverse_heap3,
middle,
upper_bound,
min_edge_offset,
DO_NOT_FORCE_LOOPS,
DO_NOT_FORCE_LOOPS);
} }
if (!reverse_heap3.Empty()) if (!reverse_heap3.Empty())
{ {
routingStep<REVERSE_DIRECTION>(facade, routingStep<REVERSE_DIRECTION>(
reverse_heap3, facade, reverse_heap3, forward_heap3, middle, upper_bound, min_edge_offset, {}, {});
forward_heap3,
middle,
upper_bound,
min_edge_offset,
DO_NOT_FORCE_LOOPS,
DO_NOT_FORCE_LOOPS);
} }
} }
return (upper_bound <= t_test_path_weight); return (upper_bound <= t_test_path_weight);
@ -566,15 +554,12 @@ bool viaNodeCandidatePassesTTest(SearchEngineData<Algorithm> &engine_working_dat
InternalManyRoutesResult alternativePathSearch(SearchEngineData<Algorithm> &engine_working_data, InternalManyRoutesResult alternativePathSearch(SearchEngineData<Algorithm> &engine_working_data,
const DataFacade<Algorithm> &facade, const DataFacade<Algorithm> &facade,
const PhantomNodes &phantom_node_pair, const PhantomEndpointCandidates &endpoint_candidates,
unsigned /*number_of_alternatives*/) unsigned /*number_of_alternatives*/)
{ {
InternalRouteResult primary_route; InternalRouteResult primary_route;
InternalRouteResult secondary_route; InternalRouteResult secondary_route;
primary_route.segment_end_coordinates = {phantom_node_pair};
secondary_route.segment_end_coordinates = {phantom_node_pair};
std::vector<NodeID> alternative_path; std::vector<NodeID> alternative_path;
std::vector<NodeID> via_node_candidate_list; std::vector<NodeID> via_node_candidate_list;
std::vector<SearchSpaceEdge> forward_search_space; std::vector<SearchSpaceEdge> forward_search_space;
@ -592,15 +577,13 @@ InternalManyRoutesResult alternativePathSearch(SearchEngineData<Algorithm> &engi
EdgeWeight upper_bound_to_shortest_path_weight = INVALID_EDGE_WEIGHT; EdgeWeight upper_bound_to_shortest_path_weight = INVALID_EDGE_WEIGHT;
NodeID middle_node = SPECIAL_NODEID; NodeID middle_node = SPECIAL_NODEID;
const EdgeWeight min_edge_offset =
std::min(phantom_node_pair.source_phantom.forward_segment_id.enabled
? -phantom_node_pair.source_phantom.GetForwardWeightPlusOffset()
: 0,
phantom_node_pair.source_phantom.reverse_segment_id.enabled
? -phantom_node_pair.source_phantom.GetReverseWeightPlusOffset()
: 0);
insertNodesInHeaps(forward_heap1, reverse_heap1, phantom_node_pair); insertNodesInHeaps(forward_heap1, reverse_heap1, endpoint_candidates);
// get offset to account for offsets on phantom nodes on compressed edges
EdgeWeight min_edge_offset = forward_heap1.Empty() ? 0 : std::min(0, forward_heap1.MinKey());
BOOST_ASSERT(min_edge_offset <= 0);
// we only every insert negative offsets for nodes in the forward heap
BOOST_ASSERT(reverse_heap1.Empty() || reverse_heap1.MinKey() >= 0);
// search from s and t till new_min/(1+epsilon) > weight_of_shortest_path // search from s and t till new_min/(1+epsilon) > weight_of_shortest_path
while (0 < (forward_heap1.Size() + reverse_heap1.Size())) while (0 < (forward_heap1.Size() + reverse_heap1.Size()))
@ -790,7 +773,7 @@ InternalManyRoutesResult alternativePathSearch(SearchEngineData<Algorithm> &engi
&v_t_middle, &v_t_middle,
min_edge_offset)) min_edge_offset))
{ {
// select first admissable // select first admissible
selected_via_node = candidate.node; selected_via_node = candidate.node;
break; break;
} }
@ -799,20 +782,23 @@ InternalManyRoutesResult alternativePathSearch(SearchEngineData<Algorithm> &engi
// Unpack shortest path and alternative, if they exist // Unpack shortest path and alternative, if they exist
if (INVALID_EDGE_WEIGHT != upper_bound_to_shortest_path_weight) if (INVALID_EDGE_WEIGHT != upper_bound_to_shortest_path_weight)
{ {
auto phantom_endpoints = endpointsFromCandidates(endpoint_candidates, packed_shortest_path);
primary_route.leg_endpoints = {phantom_endpoints};
BOOST_ASSERT(!packed_shortest_path.empty()); BOOST_ASSERT(!packed_shortest_path.empty());
primary_route.unpacked_path_segments.resize(1); primary_route.unpacked_path_segments.resize(1);
primary_route.source_traversed_in_reverse.push_back( primary_route.source_traversed_in_reverse.push_back(
(packed_shortest_path.front() != (packed_shortest_path.front() !=
phantom_node_pair.source_phantom.forward_segment_id.id)); phantom_endpoints.source_phantom.forward_segment_id.id));
primary_route.target_traversed_in_reverse.push_back(( primary_route.target_traversed_in_reverse.push_back((
packed_shortest_path.back() != phantom_node_pair.target_phantom.forward_segment_id.id)); packed_shortest_path.back() != phantom_endpoints.target_phantom.forward_segment_id.id));
unpackPath(facade, unpackPath(facade,
// -- packed input // -- packed input
packed_shortest_path.begin(), packed_shortest_path.begin(),
packed_shortest_path.end(), packed_shortest_path.end(),
// -- start of route // -- start of route
phantom_node_pair, phantom_endpoints,
// -- unpacked output // -- unpacked output
primary_route.unpacked_path_segments.front()); primary_route.unpacked_path_segments.front());
primary_route.shortest_path_weight = upper_bound_to_shortest_path_weight; primary_route.shortest_path_weight = upper_bound_to_shortest_path_weight;
@ -830,19 +816,23 @@ InternalManyRoutesResult alternativePathSearch(SearchEngineData<Algorithm> &engi
v_t_middle, v_t_middle,
packed_alternate_path); packed_alternate_path);
auto phantom_endpoints =
endpointsFromCandidates(endpoint_candidates, packed_alternate_path);
secondary_route.leg_endpoints = {phantom_endpoints};
secondary_route.unpacked_path_segments.resize(1); secondary_route.unpacked_path_segments.resize(1);
secondary_route.source_traversed_in_reverse.push_back( secondary_route.source_traversed_in_reverse.push_back(
(packed_alternate_path.front() != (packed_alternate_path.front() !=
phantom_node_pair.source_phantom.forward_segment_id.id)); phantom_endpoints.source_phantom.forward_segment_id.id));
secondary_route.target_traversed_in_reverse.push_back( secondary_route.target_traversed_in_reverse.push_back(
(packed_alternate_path.back() != (packed_alternate_path.back() !=
phantom_node_pair.target_phantom.forward_segment_id.id)); phantom_endpoints.target_phantom.forward_segment_id.id));
// unpack the alternate path // unpack the alternate path
unpackPath(facade, unpackPath(facade,
packed_alternate_path.begin(), packed_alternate_path.begin(),
packed_alternate_path.end(), packed_alternate_path.end(),
phantom_node_pair, phantom_endpoints,
secondary_route.unpacked_path_segments.front()); secondary_route.unpacked_path_segments.front());
secondary_route.shortest_path_weight = weight_of_via_path; secondary_route.shortest_path_weight = weight_of_via_path;

View File

@ -133,12 +133,13 @@ double getLongerByFactorBasedOnDuration(const EdgeWeight duration)
return a + b / (duration - d) + c / std::pow(duration - d, 3); return a + b / (duration - d) + c / std::pow(duration - d, 3);
} }
Parameters parametersFromRequest(const PhantomNodes &phantom_node_pair) Parameters parametersFromRequest(const PhantomEndpointCandidates &endpoint_candidates)
{ {
Parameters parameters; Parameters parameters;
const auto distance = util::coordinate_calculation::greatCircleDistance( const auto distance = util::coordinate_calculation::greatCircleDistance(
phantom_node_pair.source_phantom.location, phantom_node_pair.target_phantom.location); candidatesSnappedLocation(endpoint_candidates.source_phantoms),
candidatesSnappedLocation(endpoint_candidates.target_phantoms));
// 10km // 10km
if (distance < 10000.) if (distance < 10000.)
@ -547,7 +548,7 @@ void unpackPackedPaths(InputIt first,
OutIt out, OutIt out,
SearchEngineData<Algorithm> &search_engine_data, SearchEngineData<Algorithm> &search_engine_data,
const Facade &facade, const Facade &facade,
const PhantomNodes &phantom_node_pair) const PhantomEndpointCandidates &endpoint_candidates)
{ {
util::static_assert_iter_category<InputIt, std::input_iterator_tag>(); util::static_assert_iter_category<InputIt, std::input_iterator_tag>();
util::static_assert_iter_category<OutIt, std::output_iterator_tag>(); util::static_assert_iter_category<OutIt, std::output_iterator_tag>();
@ -600,7 +601,7 @@ void unpackPackedPaths(InputIt first,
} }
else else
{ // an overlay graph edge { // an overlay graph edge
LevelID level = getNodeQueryLevel(partition, source, phantom_node_pair); // XXX LevelID level = getNodeQueryLevel(partition, source, endpoint_candidates); // XXX
CellID parent_cell_id = partition.GetCell(level, source); CellID parent_cell_id = partition.GetCell(level, source);
BOOST_ASSERT(parent_cell_id == partition.GetCell(level, target)); BOOST_ASSERT(parent_cell_id == partition.GetCell(level, target));
@ -624,8 +625,8 @@ void unpackPackedPaths(InputIt first,
facade, facade,
forward_heap, forward_heap,
reverse_heap, reverse_heap,
DO_NOT_FORCE_LOOPS, {},
DO_NOT_FORCE_LOOPS, {},
INVALID_EDGE_WEIGHT, INVALID_EDGE_WEIGHT,
sublevel, sublevel,
parent_cell_id); parent_cell_id);
@ -656,13 +657,13 @@ void unpackPackedPaths(InputIt first,
inline std::vector<WeightedViaNode> inline std::vector<WeightedViaNode>
makeCandidateVias(SearchEngineData<Algorithm> &search_engine_data, makeCandidateVias(SearchEngineData<Algorithm> &search_engine_data,
const Facade &facade, const Facade &facade,
const PhantomNodes &phantom_node_pair, const PhantomEndpointCandidates &endpoint_candidates,
const Parameters &parameters) const Parameters &parameters)
{ {
Heap &forward_heap = *search_engine_data.forward_heap_1; Heap &forward_heap = *search_engine_data.forward_heap_1;
Heap &reverse_heap = *search_engine_data.reverse_heap_1; Heap &reverse_heap = *search_engine_data.reverse_heap_1;
insertNodesInHeaps(forward_heap, reverse_heap, phantom_node_pair); insertNodesInHeaps(forward_heap, reverse_heap, endpoint_candidates);
if (forward_heap.Empty() || reverse_heap.Empty()) if (forward_heap.Empty() || reverse_heap.Empty())
{ {
return {}; return {};
@ -712,9 +713,9 @@ makeCandidateVias(SearchEngineData<Algorithm> &search_engine_data,
reverse_heap, reverse_heap,
overlap_via, overlap_via,
overlap_weight, overlap_weight,
DO_NOT_FORCE_LOOPS, {},
DO_NOT_FORCE_LOOPS, {},
phantom_node_pair); endpoint_candidates);
if (!forward_heap.Empty()) if (!forward_heap.Empty())
forward_heap_min = forward_heap.MinKey(); forward_heap_min = forward_heap.MinKey();
@ -738,9 +739,9 @@ makeCandidateVias(SearchEngineData<Algorithm> &search_engine_data,
forward_heap, forward_heap,
overlap_via, overlap_via,
overlap_weight, overlap_weight,
DO_NOT_FORCE_LOOPS, {},
DO_NOT_FORCE_LOOPS, {},
phantom_node_pair); endpoint_candidates);
if (!reverse_heap.Empty()) if (!reverse_heap.Empty())
reverse_heap_min = reverse_heap.MinKey(); reverse_heap_min = reverse_heap.MinKey();
@ -776,10 +777,10 @@ makeCandidateVias(SearchEngineData<Algorithm> &search_engine_data,
// https://github.com/Project-OSRM/osrm-backend/issues/3905 // https://github.com/Project-OSRM/osrm-backend/issues/3905
InternalManyRoutesResult alternativePathSearch(SearchEngineData<Algorithm> &search_engine_data, InternalManyRoutesResult alternativePathSearch(SearchEngineData<Algorithm> &search_engine_data,
const Facade &facade, const Facade &facade,
const PhantomNodes &phantom_node_pair, const PhantomEndpointCandidates &endpoint_candidates,
unsigned number_of_alternatives) unsigned number_of_alternatives)
{ {
Parameters parameters = parametersFromRequest(phantom_node_pair); Parameters parameters = parametersFromRequest(endpoint_candidates);
const auto max_number_of_alternatives = number_of_alternatives; const auto max_number_of_alternatives = number_of_alternatives;
const auto max_number_of_alternatives_to_unpack = const auto max_number_of_alternatives_to_unpack =
@ -798,7 +799,7 @@ InternalManyRoutesResult alternativePathSearch(SearchEngineData<Algorithm> &sear
// Do forward and backward search, save search space overlap as via candidates. // Do forward and backward search, save search space overlap as via candidates.
auto candidate_vias = auto candidate_vias =
makeCandidateVias(search_engine_data, facade, phantom_node_pair, parameters); makeCandidateVias(search_engine_data, facade, endpoint_candidates, parameters);
const auto by_weight = [](const auto &lhs, const auto &rhs) { return lhs.weight < rhs.weight; }; const auto by_weight = [](const auto &lhs, const auto &rhs) { return lhs.weight < rhs.weight; };
auto shortest_path_via_it = auto shortest_path_via_it =
@ -813,8 +814,6 @@ InternalManyRoutesResult alternativePathSearch(SearchEngineData<Algorithm> &sear
if (!has_shortest_path) if (!has_shortest_path)
{ {
InternalRouteResult invalid; InternalRouteResult invalid;
invalid.shortest_path_weight = INVALID_EDGE_WEIGHT;
invalid.segment_end_coordinates = {phantom_node_pair};
return invalid; return invalid;
} }
@ -900,7 +899,7 @@ InternalManyRoutesResult alternativePathSearch(SearchEngineData<Algorithm> &sear
std::back_inserter(unpacked_paths), std::back_inserter(unpacked_paths),
search_engine_data, search_engine_data,
facade, facade,
phantom_node_pair); endpoint_candidates);
// //
// Filter and rank a second time. This time instead of being fast and doing // Filter and rank a second time. This time instead of being fast and doing
@ -927,7 +926,7 @@ InternalManyRoutesResult alternativePathSearch(SearchEngineData<Algorithm> &sear
routes.reserve(number_of_unpacked_paths); routes.reserve(number_of_unpacked_paths);
const auto unpacked_path_to_route = [&](const WeightedViaNodeUnpackedPath &path) { const auto unpacked_path_to_route = [&](const WeightedViaNodeUnpackedPath &path) {
return extractRoute(facade, path.via.weight, phantom_node_pair, path.nodes, path.edges); return extractRoute(facade, path.via.weight, endpoint_candidates, path.nodes, path.edges);
}; };
std::transform(unpacked_paths_first, std::transform(unpacked_paths_first,

View File

@ -19,7 +19,7 @@ namespace routing_algorithms
template <> template <>
InternalRouteResult directShortestPathSearch(SearchEngineData<ch::Algorithm> &engine_working_data, InternalRouteResult directShortestPathSearch(SearchEngineData<ch::Algorithm> &engine_working_data,
const DataFacade<ch::Algorithm> &facade, const DataFacade<ch::Algorithm> &facade,
const PhantomNodes &phantom_nodes) const PhantomEndpointCandidates &endpoint_candidates)
{ {
engine_working_data.InitializeOrClearFirstThreadLocalStorage(facade.GetNumberOfNodes()); engine_working_data.InitializeOrClearFirstThreadLocalStorage(facade.GetNumberOfNodes());
auto &forward_heap = *engine_working_data.forward_heap_1; auto &forward_heap = *engine_working_data.forward_heap_1;
@ -29,7 +29,7 @@ InternalRouteResult directShortestPathSearch(SearchEngineData<ch::Algorithm> &en
EdgeWeight weight = INVALID_EDGE_WEIGHT; EdgeWeight weight = INVALID_EDGE_WEIGHT;
std::vector<NodeID> packed_leg; std::vector<NodeID> packed_leg;
insertNodesInHeaps(forward_heap, reverse_heap, phantom_nodes); insertNodesInHeaps(forward_heap, reverse_heap, endpoint_candidates);
search(engine_working_data, search(engine_working_data,
facade, facade,
@ -37,9 +37,9 @@ InternalRouteResult directShortestPathSearch(SearchEngineData<ch::Algorithm> &en
reverse_heap, reverse_heap,
weight, weight,
packed_leg, packed_leg,
DO_NOT_FORCE_LOOPS, {},
DO_NOT_FORCE_LOOPS, {},
phantom_nodes); endpoint_candidates);
std::vector<NodeID> unpacked_nodes; std::vector<NodeID> unpacked_nodes;
std::vector<EdgeID> unpacked_edges; std::vector<EdgeID> unpacked_edges;
@ -60,19 +60,19 @@ InternalRouteResult directShortestPathSearch(SearchEngineData<ch::Algorithm> &en
}); });
} }
return extractRoute(facade, weight, phantom_nodes, unpacked_nodes, unpacked_edges); return extractRoute(facade, weight, endpoint_candidates, unpacked_nodes, unpacked_edges);
} }
template <> template <>
InternalRouteResult directShortestPathSearch(SearchEngineData<mld::Algorithm> &engine_working_data, InternalRouteResult directShortestPathSearch(SearchEngineData<mld::Algorithm> &engine_working_data,
const DataFacade<mld::Algorithm> &facade, const DataFacade<mld::Algorithm> &facade,
const PhantomNodes &phantom_nodes) const PhantomEndpointCandidates &endpoint_candidates)
{ {
engine_working_data.InitializeOrClearFirstThreadLocalStorage(facade.GetNumberOfNodes(), engine_working_data.InitializeOrClearFirstThreadLocalStorage(facade.GetNumberOfNodes(),
facade.GetMaxBorderNodeID() + 1); facade.GetMaxBorderNodeID() + 1);
auto &forward_heap = *engine_working_data.forward_heap_1; auto &forward_heap = *engine_working_data.forward_heap_1;
auto &reverse_heap = *engine_working_data.reverse_heap_1; auto &reverse_heap = *engine_working_data.reverse_heap_1;
insertNodesInHeaps(forward_heap, reverse_heap, phantom_nodes); insertNodesInHeaps(forward_heap, reverse_heap, endpoint_candidates);
// TODO: when structured bindings will be allowed change to // TODO: when structured bindings will be allowed change to
// auto [weight, source_node, target_node, unpacked_edges] = ... // auto [weight, source_node, target_node, unpacked_edges] = ...
@ -83,12 +83,12 @@ InternalRouteResult directShortestPathSearch(SearchEngineData<mld::Algorithm> &e
facade, facade,
forward_heap, forward_heap,
reverse_heap, reverse_heap,
DO_NOT_FORCE_LOOPS, {},
DO_NOT_FORCE_LOOPS, {},
INVALID_EDGE_WEIGHT, INVALID_EDGE_WEIGHT,
phantom_nodes); endpoint_candidates);
return extractRoute(facade, weight, phantom_nodes, unpacked_nodes, unpacked_edges); return extractRoute(facade, weight, endpoint_candidates, unpacked_nodes, unpacked_edges);
} }
} // namespace routing_algorithms } // namespace routing_algorithms

View File

@ -49,7 +49,7 @@ void relaxOutgoingEdges(
const DataFacade<Algorithm> &facade, const DataFacade<Algorithm> &facade,
const typename SearchEngineData<Algorithm>::ManyToManyQueryHeap::HeapNode &heapNode, const typename SearchEngineData<Algorithm>::ManyToManyQueryHeap::HeapNode &heapNode,
typename SearchEngineData<Algorithm>::ManyToManyQueryHeap &query_heap, typename SearchEngineData<Algorithm>::ManyToManyQueryHeap &query_heap,
const PhantomNode &) const PhantomNodeCandidates &)
{ {
if (stallAtNode<DIRECTION>(facade, heapNode, query_heap)) if (stallAtNode<DIRECTION>(facade, heapNode, query_heap))
{ {
@ -99,7 +99,7 @@ void forwardRoutingStep(const DataFacade<Algorithm> &facade,
std::vector<EdgeDuration> &durations_table, std::vector<EdgeDuration> &durations_table,
std::vector<EdgeDistance> &distances_table, std::vector<EdgeDistance> &distances_table,
std::vector<NodeID> &middle_nodes_table, std::vector<NodeID> &middle_nodes_table,
const PhantomNode &phantom_node) const PhantomNodeCandidates &candidates)
{ {
// Take a copy of the extracted node because otherwise could be modified later if toHeapNode is // Take a copy of the extracted node because otherwise could be modified later if toHeapNode is
// the same // the same
@ -151,14 +151,14 @@ void forwardRoutingStep(const DataFacade<Algorithm> &facade,
} }
} }
relaxOutgoingEdges<FORWARD_DIRECTION>(facade, heapNode, query_heap, phantom_node); relaxOutgoingEdges<FORWARD_DIRECTION>(facade, heapNode, query_heap, candidates);
} }
void backwardRoutingStep(const DataFacade<Algorithm> &facade, void backwardRoutingStep(const DataFacade<Algorithm> &facade,
const unsigned column_index, const unsigned column_index,
typename SearchEngineData<Algorithm>::ManyToManyQueryHeap &query_heap, typename SearchEngineData<Algorithm>::ManyToManyQueryHeap &query_heap,
std::vector<NodeBucket> &search_space_with_buckets, std::vector<NodeBucket> &search_space_with_buckets,
const PhantomNode &phantom_node) const PhantomNodeCandidates &candidates)
{ {
// Take a copy (no ref &) of the extracted node because otherwise could be modified later if // Take a copy (no ref &) of the extracted node because otherwise could be modified later if
// toHeapNode is the same // toHeapNode is the same
@ -172,7 +172,7 @@ void backwardRoutingStep(const DataFacade<Algorithm> &facade,
heapNode.data.duration, heapNode.data.duration,
heapNode.data.distance); heapNode.data.distance);
relaxOutgoingEdges<REVERSE_DIRECTION>(facade, heapNode, query_heap, phantom_node); relaxOutgoingEdges<REVERSE_DIRECTION>(facade, heapNode, query_heap, candidates);
} }
} // namespace ch } // namespace ch
@ -181,7 +181,7 @@ template <>
std::pair<std::vector<EdgeDuration>, std::vector<EdgeDistance>> std::pair<std::vector<EdgeDuration>, std::vector<EdgeDistance>>
manyToManySearch(SearchEngineData<ch::Algorithm> &engine_working_data, manyToManySearch(SearchEngineData<ch::Algorithm> &engine_working_data,
const DataFacade<ch::Algorithm> &facade, const DataFacade<ch::Algorithm> &facade,
const std::vector<PhantomNode> &phantom_nodes, const std::vector<PhantomNodeCandidates> &candidates_list,
const std::vector<std::size_t> &source_indices, const std::vector<std::size_t> &source_indices,
const std::vector<std::size_t> &target_indices, const std::vector<std::size_t> &target_indices,
const bool calculate_distance) const bool calculate_distance)
@ -202,18 +202,18 @@ manyToManySearch(SearchEngineData<ch::Algorithm> &engine_working_data,
for (std::uint32_t column_index = 0; column_index < target_indices.size(); ++column_index) for (std::uint32_t column_index = 0; column_index < target_indices.size(); ++column_index)
{ {
const auto index = target_indices[column_index]; const auto index = target_indices[column_index];
const auto &phantom = phantom_nodes[index]; const auto &target_candidates = candidates_list[index];
engine_working_data.InitializeOrClearManyToManyThreadLocalStorage( engine_working_data.InitializeOrClearManyToManyThreadLocalStorage(
facade.GetNumberOfNodes()); facade.GetNumberOfNodes());
auto &query_heap = *(engine_working_data.many_to_many_heap); auto &query_heap = *(engine_working_data.many_to_many_heap);
insertTargetInHeap(query_heap, phantom); insertTargetInHeap(query_heap, target_candidates);
// Explore search space // Explore search space
while (!query_heap.Empty()) while (!query_heap.Empty())
{ {
backwardRoutingStep( backwardRoutingStep(
facade, column_index, query_heap, search_space_with_buckets, phantom); facade, column_index, query_heap, search_space_with_buckets, target_candidates);
} }
} }
@ -224,13 +224,13 @@ manyToManySearch(SearchEngineData<ch::Algorithm> &engine_working_data,
for (std::uint32_t row_index = 0; row_index < source_indices.size(); ++row_index) for (std::uint32_t row_index = 0; row_index < source_indices.size(); ++row_index)
{ {
const auto source_index = source_indices[row_index]; const auto source_index = source_indices[row_index];
const auto &source_phantom = phantom_nodes[source_index]; const auto &source_candidates = candidates_list[source_index];
// Clear heap and insert source nodes // Clear heap and insert source nodes
engine_working_data.InitializeOrClearManyToManyThreadLocalStorage( engine_working_data.InitializeOrClearManyToManyThreadLocalStorage(
facade.GetNumberOfNodes()); facade.GetNumberOfNodes());
auto &query_heap = *(engine_working_data.many_to_many_heap); auto &query_heap = *(engine_working_data.many_to_many_heap);
insertSourceInHeap(query_heap, source_phantom); insertSourceInHeap(query_heap, source_candidates);
// Explore search space // Explore search space
while (!query_heap.Empty()) while (!query_heap.Empty())
@ -244,7 +244,7 @@ manyToManySearch(SearchEngineData<ch::Algorithm> &engine_working_data,
durations_table, durations_table,
distances_table, distances_table,
middle_nodes_table, middle_nodes_table,
source_phantom); source_candidates);
} }
} }

View File

@ -25,7 +25,7 @@ using PackedPath = std::vector<PackedEdge>;
template <typename MultiLevelPartition> template <typename MultiLevelPartition>
inline LevelID getNodeQueryLevel(const MultiLevelPartition &partition, inline LevelID getNodeQueryLevel(const MultiLevelPartition &partition,
const NodeID node, const NodeID node,
const PhantomNode &phantom_node, const PhantomNodeCandidates &phantom_node,
const LevelID maximal_level) const LevelID maximal_level)
{ {
const auto node_level = getNodeQueryLevel(partition, node, phantom_node); const auto node_level = getNodeQueryLevel(partition, node, phantom_node);
@ -96,7 +96,7 @@ void relaxOutgoingEdges(
const DataFacade<mld::Algorithm> &facade, const DataFacade<mld::Algorithm> &facade,
const typename SearchEngineData<mld::Algorithm>::ManyToManyQueryHeap::HeapNode &heapNode, const typename SearchEngineData<mld::Algorithm>::ManyToManyQueryHeap::HeapNode &heapNode,
typename SearchEngineData<mld::Algorithm>::ManyToManyQueryHeap &query_heap, typename SearchEngineData<mld::Algorithm>::ManyToManyQueryHeap &query_heap,
Args... args) const Args &... args)
{ {
BOOST_ASSERT(!facade.ExcludeNode(heapNode.node)); BOOST_ASSERT(!facade.ExcludeNode(heapNode.node));
@ -214,26 +214,27 @@ template <bool DIRECTION>
std::pair<std::vector<EdgeDuration>, std::vector<EdgeDistance>> std::pair<std::vector<EdgeDuration>, std::vector<EdgeDistance>>
oneToManySearch(SearchEngineData<Algorithm> &engine_working_data, oneToManySearch(SearchEngineData<Algorithm> &engine_working_data,
const DataFacade<Algorithm> &facade, const DataFacade<Algorithm> &facade,
const std::vector<PhantomNode> &phantom_nodes, const std::vector<PhantomNodeCandidates> &candidates_list,
std::size_t phantom_index, std::size_t source_index,
const std::vector<std::size_t> &phantom_indices, const std::vector<std::size_t> &target_indices,
const bool calculate_distance) const bool calculate_distance)
{ {
std::vector<EdgeWeight> weights_table(phantom_indices.size(), INVALID_EDGE_WEIGHT); std::vector<EdgeWeight> weights_table(target_indices.size(), INVALID_EDGE_WEIGHT);
std::vector<EdgeDuration> durations_table(phantom_indices.size(), MAXIMAL_EDGE_DURATION); std::vector<EdgeDuration> durations_table(target_indices.size(), MAXIMAL_EDGE_DURATION);
std::vector<EdgeDistance> distances_table(calculate_distance ? phantom_indices.size() : 0, std::vector<EdgeDistance> distances_table(calculate_distance ? target_indices.size() : 0,
MAXIMAL_EDGE_DISTANCE); MAXIMAL_EDGE_DISTANCE);
std::vector<NodeID> middle_nodes_table(phantom_indices.size(), SPECIAL_NODEID); std::vector<NodeID> middle_nodes_table(target_indices.size(), SPECIAL_NODEID);
// Collect destination (source) nodes into a map // Collect destination (source) nodes into a map
std::unordered_multimap<NodeID, std::tuple<std::size_t, EdgeWeight, EdgeDuration, EdgeDistance>> std::unordered_multimap<NodeID, std::tuple<std::size_t, EdgeWeight, EdgeDuration, EdgeDistance>>
target_nodes_index; target_nodes_index;
target_nodes_index.reserve(phantom_indices.size()); target_nodes_index.reserve(target_indices.size());
for (std::size_t index = 0; index < phantom_indices.size(); ++index) for (std::size_t index = 0; index < target_indices.size(); ++index)
{ {
const auto &phantom_index = phantom_indices[index]; const auto &target_candidates = candidates_list[target_indices[index]];
const auto &phantom_node = phantom_nodes[phantom_index];
for (const auto &phantom_node : target_candidates)
{
if (DIRECTION == FORWARD_DIRECTION) if (DIRECTION == FORWARD_DIRECTION)
{ {
if (phantom_node.IsValidForwardTarget()) if (phantom_node.IsValidForwardTarget())
@ -243,6 +244,7 @@ oneToManySearch(SearchEngineData<Algorithm> &engine_working_data,
phantom_node.GetForwardWeightPlusOffset(), phantom_node.GetForwardWeightPlusOffset(),
phantom_node.GetForwardDuration(), phantom_node.GetForwardDuration(),
phantom_node.GetForwardDistance())}); phantom_node.GetForwardDistance())});
if (phantom_node.IsValidReverseTarget()) if (phantom_node.IsValidReverseTarget())
target_nodes_index.insert( target_nodes_index.insert(
{phantom_node.reverse_segment_id.id, {phantom_node.reverse_segment_id.id,
@ -260,6 +262,7 @@ oneToManySearch(SearchEngineData<Algorithm> &engine_working_data,
-phantom_node.GetForwardWeightPlusOffset(), -phantom_node.GetForwardWeightPlusOffset(),
-phantom_node.GetForwardDuration(), -phantom_node.GetForwardDuration(),
-phantom_node.GetForwardDistance())}); -phantom_node.GetForwardDistance())});
if (phantom_node.IsValidReverseSource()) if (phantom_node.IsValidReverseSource())
target_nodes_index.insert( target_nodes_index.insert(
{phantom_node.reverse_segment_id.id, {phantom_node.reverse_segment_id.id,
@ -269,6 +272,7 @@ oneToManySearch(SearchEngineData<Algorithm> &engine_working_data,
-phantom_node.GetReverseDistance())}); -phantom_node.GetReverseDistance())});
} }
} }
}
// Initialize query heap // Initialize query heap
engine_working_data.InitializeOrClearManyToManyThreadLocalStorage( engine_working_data.InitializeOrClearManyToManyThreadLocalStorage(
@ -337,8 +341,10 @@ oneToManySearch(SearchEngineData<Algorithm> &engine_working_data,
}; };
{ // Place source (destination) adjacent nodes into the heap { // Place source (destination) adjacent nodes into the heap
const auto &phantom_node = phantom_nodes[phantom_index]; const auto &source_candidates = candidates_list[source_index];
for (const auto &phantom_node : source_candidates)
{
if (DIRECTION == FORWARD_DIRECTION) if (DIRECTION == FORWARD_DIRECTION)
{ {
if (phantom_node.IsValidForwardSource()) if (phantom_node.IsValidForwardSource())
@ -376,6 +382,7 @@ oneToManySearch(SearchEngineData<Algorithm> &engine_working_data,
} }
} }
} }
}
while (!query_heap.Empty() && !target_nodes_index.empty()) while (!query_heap.Empty() && !target_nodes_index.empty())
{ {
@ -389,7 +396,7 @@ oneToManySearch(SearchEngineData<Algorithm> &engine_working_data,
// Relax outgoing edges // Relax outgoing edges
relaxOutgoingEdges<DIRECTION>( relaxOutgoingEdges<DIRECTION>(
facade, heapNode, query_heap, phantom_nodes, phantom_index, phantom_indices); facade, heapNode, query_heap, candidates_list, source_index, target_indices);
} }
return std::make_pair(std::move(durations_table), std::move(distances_table)); return std::make_pair(std::move(durations_table), std::move(distances_table));
@ -409,7 +416,7 @@ void forwardRoutingStep(const DataFacade<Algorithm> &facade,
std::vector<EdgeDuration> &durations_table, std::vector<EdgeDuration> &durations_table,
std::vector<EdgeDistance> &distances_table, std::vector<EdgeDistance> &distances_table,
std::vector<NodeID> &middle_nodes_table, std::vector<NodeID> &middle_nodes_table,
const PhantomNode &phantom_node) const PhantomNodeCandidates &candidates)
{ {
// Take a copy of the extracted node because otherwise could be modified later if toHeapNode is // Take a copy of the extracted node because otherwise could be modified later if toHeapNode is
// the same // the same
@ -455,7 +462,7 @@ void forwardRoutingStep(const DataFacade<Algorithm> &facade,
} }
} }
relaxOutgoingEdges<DIRECTION>(facade, heapNode, query_heap, phantom_node); relaxOutgoingEdges<DIRECTION>(facade, heapNode, query_heap, candidates);
} }
template <bool DIRECTION> template <bool DIRECTION>
@ -463,7 +470,7 @@ void backwardRoutingStep(const DataFacade<Algorithm> &facade,
const unsigned column_idx, const unsigned column_idx,
typename SearchEngineData<Algorithm>::ManyToManyQueryHeap &query_heap, typename SearchEngineData<Algorithm>::ManyToManyQueryHeap &query_heap,
std::vector<NodeBucket> &search_space_with_buckets, std::vector<NodeBucket> &search_space_with_buckets,
const PhantomNode &phantom_node) const PhantomNodeCandidates &candidates)
{ {
// Take a copy of the extracted node because otherwise could be modified later if toHeapNode is // Take a copy of the extracted node because otherwise could be modified later if toHeapNode is
// the same // the same
@ -481,7 +488,7 @@ void backwardRoutingStep(const DataFacade<Algorithm> &facade,
const auto &partition = facade.GetMultiLevelPartition(); const auto &partition = facade.GetMultiLevelPartition();
const auto maximal_level = partition.GetNumberOfLevels() - 1; const auto maximal_level = partition.GetNumberOfLevels() - 1;
relaxOutgoingEdges<!DIRECTION>(facade, heapNode, query_heap, phantom_node, maximal_level); relaxOutgoingEdges<!DIRECTION>(facade, heapNode, query_heap, candidates, maximal_level);
} }
template <bool DIRECTION> template <bool DIRECTION>
@ -524,7 +531,7 @@ template <bool DIRECTION>
std::pair<std::vector<EdgeDuration>, std::vector<EdgeDistance>> std::pair<std::vector<EdgeDuration>, std::vector<EdgeDistance>>
manyToManySearch(SearchEngineData<Algorithm> &engine_working_data, manyToManySearch(SearchEngineData<Algorithm> &engine_working_data,
const DataFacade<Algorithm> &facade, const DataFacade<Algorithm> &facade,
const std::vector<PhantomNode> &phantom_nodes, const std::vector<PhantomNodeCandidates> &candidates_list,
const std::vector<std::size_t> &source_indices, const std::vector<std::size_t> &source_indices,
const std::vector<std::size_t> &target_indices, const std::vector<std::size_t> &target_indices,
const bool calculate_distance) const bool calculate_distance)
@ -545,22 +552,22 @@ manyToManySearch(SearchEngineData<Algorithm> &engine_working_data,
for (std::uint32_t column_idx = 0; column_idx < target_indices.size(); ++column_idx) for (std::uint32_t column_idx = 0; column_idx < target_indices.size(); ++column_idx)
{ {
const auto index = target_indices[column_idx]; const auto index = target_indices[column_idx];
const auto &target_phantom = phantom_nodes[index]; const auto &target_candidates = candidates_list[index];
engine_working_data.InitializeOrClearManyToManyThreadLocalStorage( engine_working_data.InitializeOrClearManyToManyThreadLocalStorage(
facade.GetNumberOfNodes(), facade.GetMaxBorderNodeID() + 1); facade.GetNumberOfNodes(), facade.GetMaxBorderNodeID() + 1);
auto &query_heap = *(engine_working_data.many_to_many_heap); auto &query_heap = *(engine_working_data.many_to_many_heap);
if (DIRECTION == FORWARD_DIRECTION) if (DIRECTION == FORWARD_DIRECTION)
insertTargetInHeap(query_heap, target_phantom); insertTargetInHeap(query_heap, target_candidates);
else else
insertSourceInHeap(query_heap, target_phantom); insertSourceInHeap(query_heap, target_candidates);
// explore search space // explore search space
while (!query_heap.Empty()) while (!query_heap.Empty())
{ {
backwardRoutingStep<DIRECTION>( backwardRoutingStep<DIRECTION>(
facade, column_idx, query_heap, search_space_with_buckets, target_phantom); facade, column_idx, query_heap, search_space_with_buckets, target_candidates);
} }
} }
@ -571,7 +578,7 @@ manyToManySearch(SearchEngineData<Algorithm> &engine_working_data,
for (std::uint32_t row_idx = 0; row_idx < source_indices.size(); ++row_idx) for (std::uint32_t row_idx = 0; row_idx < source_indices.size(); ++row_idx)
{ {
const auto source_index = source_indices[row_idx]; const auto source_index = source_indices[row_idx];
const auto &source_phantom = phantom_nodes[source_index]; const auto &source_candidates = candidates_list[source_index];
// Clear heap and insert source nodes // Clear heap and insert source nodes
engine_working_data.InitializeOrClearManyToManyThreadLocalStorage( engine_working_data.InitializeOrClearManyToManyThreadLocalStorage(
@ -580,9 +587,9 @@ manyToManySearch(SearchEngineData<Algorithm> &engine_working_data,
auto &query_heap = *(engine_working_data.many_to_many_heap); auto &query_heap = *(engine_working_data.many_to_many_heap);
if (DIRECTION == FORWARD_DIRECTION) if (DIRECTION == FORWARD_DIRECTION)
insertSourceInHeap(query_heap, source_phantom); insertSourceInHeap(query_heap, source_candidates);
else else
insertTargetInHeap(query_heap, source_phantom); insertTargetInHeap(query_heap, source_candidates);
// Explore search space // Explore search space
while (!query_heap.Empty()) while (!query_heap.Empty())
@ -597,7 +604,7 @@ manyToManySearch(SearchEngineData<Algorithm> &engine_working_data,
durations_table, durations_table,
distances_table, distances_table,
middle_nodes_table, middle_nodes_table,
source_phantom); source_candidates);
} }
} }
@ -622,7 +629,7 @@ template <>
std::pair<std::vector<EdgeDuration>, std::vector<EdgeDistance>> std::pair<std::vector<EdgeDuration>, std::vector<EdgeDistance>>
manyToManySearch(SearchEngineData<mld::Algorithm> &engine_working_data, manyToManySearch(SearchEngineData<mld::Algorithm> &engine_working_data,
const DataFacade<mld::Algorithm> &facade, const DataFacade<mld::Algorithm> &facade,
const std::vector<PhantomNode> &phantom_nodes, const std::vector<PhantomNodeCandidates> &candidates_list,
const std::vector<std::size_t> &source_indices, const std::vector<std::size_t> &source_indices,
const std::vector<std::size_t> &target_indices, const std::vector<std::size_t> &target_indices,
const bool calculate_distance) const bool calculate_distance)
@ -631,7 +638,7 @@ manyToManySearch(SearchEngineData<mld::Algorithm> &engine_working_data,
{ // TODO: check if target_indices.size() == 1 and do a bi-directional search { // TODO: check if target_indices.size() == 1 and do a bi-directional search
return mld::oneToManySearch<FORWARD_DIRECTION>(engine_working_data, return mld::oneToManySearch<FORWARD_DIRECTION>(engine_working_data,
facade, facade,
phantom_nodes, candidates_list,
source_indices.front(), source_indices.front(),
target_indices, target_indices,
calculate_distance); calculate_distance);
@ -641,7 +648,7 @@ manyToManySearch(SearchEngineData<mld::Algorithm> &engine_working_data,
{ {
return mld::oneToManySearch<REVERSE_DIRECTION>(engine_working_data, return mld::oneToManySearch<REVERSE_DIRECTION>(engine_working_data,
facade, facade,
phantom_nodes, candidates_list,
target_indices.front(), target_indices.front(),
source_indices, source_indices,
calculate_distance); calculate_distance);
@ -651,7 +658,7 @@ manyToManySearch(SearchEngineData<mld::Algorithm> &engine_working_data,
{ {
return mld::manyToManySearch<REVERSE_DIRECTION>(engine_working_data, return mld::manyToManySearch<REVERSE_DIRECTION>(engine_working_data,
facade, facade,
phantom_nodes, candidates_list,
target_indices, target_indices,
source_indices, source_indices,
calculate_distance); calculate_distance);
@ -659,7 +666,7 @@ manyToManySearch(SearchEngineData<mld::Algorithm> &engine_working_data,
return mld::manyToManySearch<FORWARD_DIRECTION>(engine_working_data, return mld::manyToManySearch<FORWARD_DIRECTION>(engine_working_data,
facade, facade,
phantom_nodes, candidates_list,
source_indices, source_indices,
target_indices, target_indices,
calculate_distance); calculate_distance);

View File

@ -7,30 +7,104 @@ namespace engine
namespace routing_algorithms namespace routing_algorithms
{ {
bool needsLoopForward(const PhantomNode &source_phantom, const PhantomNode &target_phantom) bool requiresForwardLoop(const PhantomNode &source, const PhantomNode &target)
{ {
return source_phantom.IsValidForwardSource() && target_phantom.IsValidForwardTarget() && return source.IsValidForwardSource() && target.IsValidForwardTarget() &&
source_phantom.forward_segment_id.id == target_phantom.forward_segment_id.id && source.forward_segment_id.id == target.forward_segment_id.id &&
source_phantom.GetForwardWeightPlusOffset() > source.GetForwardWeightPlusOffset() > target.GetForwardWeightPlusOffset();
target_phantom.GetForwardWeightPlusOffset();
} }
bool needsLoopBackwards(const PhantomNode &source_phantom, const PhantomNode &target_phantom) bool requiresBackwardLoop(const PhantomNode &source, const PhantomNode &target)
{ {
return source_phantom.IsValidReverseSource() && target_phantom.IsValidReverseTarget() && return source.IsValidReverseSource() && target.IsValidReverseTarget() &&
source_phantom.reverse_segment_id.id == target_phantom.reverse_segment_id.id && source.reverse_segment_id.id == target.reverse_segment_id.id &&
source_phantom.GetReverseWeightPlusOffset() > source.GetReverseWeightPlusOffset() > target.GetReverseWeightPlusOffset();
target_phantom.GetReverseWeightPlusOffset();
} }
bool needsLoopForward(const PhantomNodes &phantoms) std::vector<NodeID> getForwardLoopNodes(const PhantomEndpointCandidates &endpoint_candidates)
{ {
return needsLoopForward(phantoms.source_phantom, phantoms.target_phantom); std::vector<NodeID> res;
for (const auto &source_phantom : endpoint_candidates.source_phantoms)
{
auto requires_loop =
std::any_of(endpoint_candidates.target_phantoms.begin(),
endpoint_candidates.target_phantoms.end(),
[&](const auto &target_phantom) {
return requiresForwardLoop(source_phantom, target_phantom);
});
if (requires_loop)
{
res.push_back(source_phantom.forward_segment_id.id);
}
}
return res;
} }
bool needsLoopBackwards(const PhantomNodes &phantoms) std::vector<NodeID> getForwardLoopNodes(const PhantomCandidatesToTarget &endpoint_candidates)
{ {
return needsLoopBackwards(phantoms.source_phantom, phantoms.target_phantom); std::vector<NodeID> res;
for (const auto &source_phantom : endpoint_candidates.source_phantoms)
{
if (requiresForwardLoop(source_phantom, endpoint_candidates.target_phantom))
{
res.push_back(source_phantom.forward_segment_id.id);
}
}
return res;
}
std::vector<NodeID> getBackwardLoopNodes(const PhantomEndpointCandidates &endpoint_candidates)
{
std::vector<NodeID> res;
for (const auto &source_phantom : endpoint_candidates.source_phantoms)
{
auto requires_loop =
std::any_of(endpoint_candidates.target_phantoms.begin(),
endpoint_candidates.target_phantoms.end(),
[&](const auto &target_phantom) {
return requiresBackwardLoop(source_phantom, target_phantom);
});
if (requires_loop)
{
res.push_back(source_phantom.reverse_segment_id.id);
}
}
return res;
}
std::vector<NodeID> getBackwardLoopNodes(const PhantomCandidatesToTarget &endpoint_candidates)
{
std::vector<NodeID> res;
for (const auto &source_phantom : endpoint_candidates.source_phantoms)
{
if (requiresBackwardLoop(source_phantom, endpoint_candidates.target_phantom))
{
res.push_back(source_phantom.reverse_segment_id.id);
}
}
return res;
}
PhantomEndpoints endpointsFromCandidates(const PhantomEndpointCandidates &candidates,
const std::vector<NodeID> &path)
{
auto source_it = std::find_if(candidates.source_phantoms.begin(),
candidates.source_phantoms.end(),
[&path](const auto &source_phantom) {
return path.front() == source_phantom.forward_segment_id.id ||
path.front() == source_phantom.reverse_segment_id.id;
});
BOOST_ASSERT(source_it != candidates.source_phantoms.end());
auto target_it = std::find_if(candidates.target_phantoms.begin(),
candidates.target_phantoms.end(),
[&path](const auto &target_phantom) {
return path.back() == target_phantom.forward_segment_id.id ||
path.back() == target_phantom.reverse_segment_id.id;
});
BOOST_ASSERT(target_it != candidates.target_phantoms.end());
return PhantomEndpoints{*source_it, *target_it};
} }
} // namespace routing_algorithms } // namespace routing_algorithms

View File

@ -95,9 +95,8 @@ void search(SearchEngineData<Algorithm> & /*engine_working_data*/,
SearchEngineData<Algorithm>::QueryHeap &reverse_heap, SearchEngineData<Algorithm>::QueryHeap &reverse_heap,
EdgeWeight &weight, EdgeWeight &weight,
std::vector<NodeID> &packed_leg, std::vector<NodeID> &packed_leg,
const bool force_loop_forward, const std::vector<NodeID> &force_loop_forward_nodes,
const bool force_loop_reverse, const std::vector<NodeID> &force_loop_reverse_nodes,
const PhantomNodes & /*phantom_nodes*/,
const EdgeWeight weight_upper_bound) const EdgeWeight weight_upper_bound)
{ {
if (forward_heap.Empty() || reverse_heap.Empty()) if (forward_heap.Empty() || reverse_heap.Empty())
@ -126,8 +125,8 @@ void search(SearchEngineData<Algorithm> & /*engine_working_data*/,
middle, middle,
weight, weight,
min_edge_offset, min_edge_offset,
force_loop_forward, force_loop_forward_nodes,
force_loop_reverse); force_loop_reverse_nodes);
} }
if (!reverse_heap.Empty()) if (!reverse_heap.Empty())
{ {
@ -137,8 +136,8 @@ void search(SearchEngineData<Algorithm> & /*engine_working_data*/,
middle, middle,
weight, weight,
min_edge_offset, min_edge_offset,
force_loop_reverse, force_loop_reverse_nodes,
force_loop_forward); force_loop_forward_nodes);
} }
} }
@ -179,7 +178,8 @@ double getNetworkDistance(SearchEngineData<Algorithm> &engine_working_data,
forward_heap.Clear(); forward_heap.Clear();
reverse_heap.Clear(); reverse_heap.Clear();
insertNodesInHeaps(forward_heap, reverse_heap, {source_phantom, target_phantom}); PhantomEndpoints endpoints{source_phantom, target_phantom};
insertNodesInHeaps(forward_heap, reverse_heap, endpoints);
EdgeWeight weight = INVALID_EDGE_WEIGHT; EdgeWeight weight = INVALID_EDGE_WEIGHT;
std::vector<NodeID> packed_path; std::vector<NodeID> packed_path;
@ -189,9 +189,9 @@ double getNetworkDistance(SearchEngineData<Algorithm> &engine_working_data,
reverse_heap, reverse_heap,
weight, weight,
packed_path, packed_path,
DO_NOT_FORCE_LOOPS, {},
DO_NOT_FORCE_LOOPS, {},
{source_phantom, target_phantom}, endpoints,
weight_upper_bound); weight_upper_bound);
if (weight == INVALID_EDGE_WEIGHT) if (weight == INVALID_EDGE_WEIGHT)

View File

@ -12,13 +12,13 @@ namespace routing_algorithms
template InternalRouteResult template InternalRouteResult
shortestPathSearch(SearchEngineData<ch::Algorithm> &engine_working_data, shortestPathSearch(SearchEngineData<ch::Algorithm> &engine_working_data,
const DataFacade<ch::Algorithm> &facade, const DataFacade<ch::Algorithm> &facade,
const std::vector<PhantomNodes> &phantom_nodes_vector, const std::vector<PhantomNodeCandidates> &waypoint_candidates,
const boost::optional<bool> continue_straight_at_waypoint); const boost::optional<bool> continue_straight_at_waypoint);
template InternalRouteResult template InternalRouteResult
shortestPathSearch(SearchEngineData<mld::Algorithm> &engine_working_data, shortestPathSearch(SearchEngineData<mld::Algorithm> &engine_working_data,
const DataFacade<mld::Algorithm> &facade, const DataFacade<mld::Algorithm> &facade,
const std::vector<PhantomNodes> &phantom_nodes_vector, const std::vector<PhantomNodeCandidates> &waypoint_candidates,
const boost::optional<bool> continue_straight_at_waypoint); const boost::optional<bool> continue_straight_at_waypoint);
} // namespace routing_algorithms } // namespace routing_algorithms

View File

@ -44,16 +44,16 @@ BOOST_AUTO_TEST_CASE(hint_encoding_decoding_roundtrip)
const PhantomNode phantom; const PhantomNode phantom;
const osrm::test::MockDataFacade<osrm::engine::routing_algorithms::ch::Algorithm> facade{}; const osrm::test::MockDataFacade<osrm::engine::routing_algorithms::ch::Algorithm> facade{};
const Hint hint{phantom, facade.GetCheckSum()}; const SegmentHint seg_hint{phantom, facade.GetCheckSum()};
const auto base64 = hint.ToBase64(); const auto base64 = seg_hint.ToBase64();
BOOST_CHECK(0 == std::count(begin(base64), end(base64), '+')); BOOST_CHECK(0 == std::count(begin(base64), end(base64), '+'));
BOOST_CHECK(0 == std::count(begin(base64), end(base64), '/')); BOOST_CHECK(0 == std::count(begin(base64), end(base64), '/'));
const auto decoded = Hint::FromBase64(base64); const auto decoded = SegmentHint::FromBase64(base64);
BOOST_CHECK_EQUAL(hint, decoded); BOOST_CHECK_EQUAL(seg_hint, decoded);
} }
BOOST_AUTO_TEST_CASE(hint_encoding_decoding_roundtrip_bytewise) BOOST_AUTO_TEST_CASE(hint_encoding_decoding_roundtrip_bytewise)
@ -65,12 +65,12 @@ BOOST_AUTO_TEST_CASE(hint_encoding_decoding_roundtrip_bytewise)
const PhantomNode phantom; const PhantomNode phantom;
const osrm::test::MockDataFacade<osrm::engine::routing_algorithms::ch::Algorithm> facade{}; const osrm::test::MockDataFacade<osrm::engine::routing_algorithms::ch::Algorithm> facade{};
const Hint hint{phantom, facade.GetCheckSum()}; const SegmentHint seg_hint{phantom, facade.GetCheckSum()};
const auto decoded = Hint::FromBase64(hint.ToBase64()); const auto decoded = SegmentHint::FromBase64(seg_hint.ToBase64());
BOOST_CHECK(std::equal(reinterpret_cast<const unsigned char *>(&hint), BOOST_CHECK(std::equal(reinterpret_cast<const unsigned char *>(&seg_hint),
reinterpret_cast<const unsigned char *>(&hint) + sizeof(Hint), reinterpret_cast<const unsigned char *>(&seg_hint) + sizeof(Hint),
reinterpret_cast<const unsigned char *>(&decoded))); reinterpret_cast<const unsigned char *>(&decoded)));
} }

View File

@ -23,7 +23,7 @@ BOOST_AUTO_TEST_CASE(unchanged_collapse_route_result)
PathData kathy{0, 1, 1, 2, 3, 4, 1, boost::none}; PathData kathy{0, 1, 1, 2, 3, 4, 1, boost::none};
InternalRouteResult one_leg_result; InternalRouteResult one_leg_result;
one_leg_result.unpacked_path_segments = {{pathy, kathy}}; one_leg_result.unpacked_path_segments = {{pathy, kathy}};
one_leg_result.segment_end_coordinates = {PhantomNodes{source, target}}; one_leg_result.leg_endpoints = {PhantomEndpoints{source, target}};
one_leg_result.source_traversed_in_reverse = {true}; one_leg_result.source_traversed_in_reverse = {true};
one_leg_result.target_traversed_in_reverse = {true}; one_leg_result.target_traversed_in_reverse = {true};
one_leg_result.shortest_path_weight = 50; one_leg_result.shortest_path_weight = 50;
@ -50,18 +50,17 @@ BOOST_AUTO_TEST_CASE(two_legs_to_one_leg)
node_3.forward_segment_id = {12, true}; node_3.forward_segment_id = {12, true};
InternalRouteResult two_leg_result; InternalRouteResult two_leg_result;
two_leg_result.unpacked_path_segments = {{pathy, kathy}, {kathy, cathy}}; two_leg_result.unpacked_path_segments = {{pathy, kathy}, {kathy, cathy}};
two_leg_result.segment_end_coordinates = {PhantomNodes{node_1, node_2}, two_leg_result.leg_endpoints = {PhantomEndpoints{node_1, node_2},
PhantomNodes{node_2, node_3}}; PhantomEndpoints{node_2, node_3}};
two_leg_result.source_traversed_in_reverse = {true, false}; two_leg_result.source_traversed_in_reverse = {true, false};
two_leg_result.target_traversed_in_reverse = {true, false}; two_leg_result.target_traversed_in_reverse = {true, false};
two_leg_result.shortest_path_weight = 80; two_leg_result.shortest_path_weight = 80;
auto collapsed = CollapseInternalRouteResult(two_leg_result, {true, false, true, true}); auto collapsed = CollapseInternalRouteResult(two_leg_result, {true, false, true, true});
BOOST_CHECK_EQUAL(collapsed.unpacked_path_segments.size(), 1); BOOST_CHECK_EQUAL(collapsed.unpacked_path_segments.size(), 1);
BOOST_CHECK_EQUAL(collapsed.segment_end_coordinates.size(), 1); BOOST_CHECK_EQUAL(collapsed.leg_endpoints.size(), 1);
BOOST_CHECK_EQUAL(collapsed.segment_end_coordinates[0].target_phantom.forward_segment_id.id, BOOST_CHECK_EQUAL(collapsed.leg_endpoints[0].target_phantom.forward_segment_id.id, 12);
12); BOOST_CHECK_EQUAL(collapsed.leg_endpoints[0].source_phantom.forward_segment_id.id, 1);
BOOST_CHECK_EQUAL(collapsed.segment_end_coordinates[0].source_phantom.forward_segment_id.id, 1);
BOOST_CHECK_EQUAL(collapsed.unpacked_path_segments[0].size(), 4); BOOST_CHECK_EQUAL(collapsed.unpacked_path_segments[0].size(), 4);
BOOST_CHECK_EQUAL(collapsed.unpacked_path_segments[0][0].turn_via_node, 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[0][1].turn_via_node, 1);
@ -88,20 +87,20 @@ BOOST_AUTO_TEST_CASE(three_legs_to_two_legs)
three_leg_result.unpacked_path_segments = {std::vector<PathData>{pathy, kathy}, three_leg_result.unpacked_path_segments = {std::vector<PathData>{pathy, kathy},
std::vector<PathData>{kathy, qathy, cathy}, std::vector<PathData>{kathy, qathy, cathy},
std::vector<PathData>{cathy, mathy}}; std::vector<PathData>{cathy, mathy}};
three_leg_result.segment_end_coordinates = { three_leg_result.leg_endpoints = {PhantomEndpoints{node_1, node_2},
PhantomNodes{node_1, node_2}, PhantomNodes{node_2, node_3}, PhantomNodes{node_3, node_4}}; PhantomEndpoints{node_2, node_3},
PhantomEndpoints{node_3, node_4}};
three_leg_result.source_traversed_in_reverse = {true, false, true}, three_leg_result.source_traversed_in_reverse = {true, false, true},
three_leg_result.target_traversed_in_reverse = {true, false, true}, three_leg_result.target_traversed_in_reverse = {true, false, true},
three_leg_result.shortest_path_weight = 140; three_leg_result.shortest_path_weight = 140;
auto collapsed = CollapseInternalRouteResult(three_leg_result, {true, true, false, true}); auto collapsed = CollapseInternalRouteResult(three_leg_result, {true, true, false, true});
BOOST_CHECK_EQUAL(collapsed.unpacked_path_segments.size(), 2); BOOST_CHECK_EQUAL(collapsed.unpacked_path_segments.size(), 2);
BOOST_CHECK_EQUAL(collapsed.segment_end_coordinates.size(), 2); BOOST_CHECK_EQUAL(collapsed.leg_endpoints.size(), 2);
BOOST_CHECK_EQUAL(collapsed.segment_end_coordinates[0].source_phantom.forward_segment_id.id, 1); BOOST_CHECK_EQUAL(collapsed.leg_endpoints[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.leg_endpoints[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.leg_endpoints[1].source_phantom.forward_segment_id.id, 6);
BOOST_CHECK_EQUAL(collapsed.segment_end_coordinates[1].target_phantom.forward_segment_id.id, BOOST_CHECK_EQUAL(collapsed.leg_endpoints[1].target_phantom.forward_segment_id.id, 18);
18);
BOOST_CHECK_EQUAL(collapsed.unpacked_path_segments[0].size(), 2); BOOST_CHECK_EQUAL(collapsed.unpacked_path_segments[0].size(), 2);
BOOST_CHECK_EQUAL(collapsed.unpacked_path_segments[1].size(), 5); BOOST_CHECK_EQUAL(collapsed.unpacked_path_segments[1].size(), 5);
BOOST_CHECK_EQUAL(collapsed.unpacked_path_segments[0][0].turn_via_node, 2); BOOST_CHECK_EQUAL(collapsed.unpacked_path_segments[0][0].turn_via_node, 2);
@ -126,20 +125,19 @@ BOOST_AUTO_TEST_CASE(two_legs_to_two_legs)
node_3.forward_segment_id = {12, true}; node_3.forward_segment_id = {12, true};
InternalRouteResult two_leg_result; InternalRouteResult two_leg_result;
two_leg_result.unpacked_path_segments = {{pathy, kathy}, {kathy, cathy}}; two_leg_result.unpacked_path_segments = {{pathy, kathy}, {kathy, cathy}};
two_leg_result.segment_end_coordinates = {PhantomNodes{node_1, node_2}, two_leg_result.leg_endpoints = {PhantomEndpoints{node_1, node_2},
PhantomNodes{node_2, node_3}}; PhantomEndpoints{node_2, node_3}};
two_leg_result.source_traversed_in_reverse = {true, false}; two_leg_result.source_traversed_in_reverse = {true, false};
two_leg_result.target_traversed_in_reverse = {true, false}; two_leg_result.target_traversed_in_reverse = {true, false};
two_leg_result.shortest_path_weight = 80; two_leg_result.shortest_path_weight = 80;
auto collapsed = CollapseInternalRouteResult(two_leg_result, {true, true, true}); auto collapsed = CollapseInternalRouteResult(two_leg_result, {true, true, true});
BOOST_CHECK_EQUAL(collapsed.unpacked_path_segments.size(), 2); BOOST_CHECK_EQUAL(collapsed.unpacked_path_segments.size(), 2);
BOOST_CHECK_EQUAL(collapsed.segment_end_coordinates.size(), 2); BOOST_CHECK_EQUAL(collapsed.leg_endpoints.size(), 2);
BOOST_CHECK_EQUAL(collapsed.segment_end_coordinates[0].source_phantom.forward_segment_id.id, 1); BOOST_CHECK_EQUAL(collapsed.leg_endpoints[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.leg_endpoints[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.leg_endpoints[1].source_phantom.forward_segment_id.id, 6);
BOOST_CHECK_EQUAL(collapsed.segment_end_coordinates[1].target_phantom.forward_segment_id.id, BOOST_CHECK_EQUAL(collapsed.leg_endpoints[1].target_phantom.forward_segment_id.id, 12);
12);
BOOST_CHECK_EQUAL(collapsed.unpacked_path_segments[0].size(), 2); 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[1].size(), 2);
BOOST_CHECK_EQUAL(collapsed.unpacked_path_segments[0][0].turn_via_node, 2); BOOST_CHECK_EQUAL(collapsed.unpacked_path_segments[0][0].turn_via_node, 2);

View File

@ -224,101 +224,35 @@ class ContiguousInternalMemoryDataFacade<routing_algorithms::offline::Algorithm>
return {}; return {};
} }
std::vector<PhantomNodeWithDistance> std::vector<engine::PhantomNodeWithDistance>
NearestPhantomNodesInRange(const util::Coordinate /*input_coordinate*/, NearestPhantomNodesInRange(const util::Coordinate /*input_coordinate*/,
const float /*max_distance*/, const double /*max_distance*/,
const int /*bearing*/, const boost::optional<engine::Bearing> /*bearing*/,
const int /*bearing_range*/, const engine::Approach /*approach*/,
const Approach /*approach*/,
const bool /*use_all_edges*/) const override const bool /*use_all_edges*/) const override
{ {
return {}; return {};
} };
std::vector<PhantomNodeWithDistance> std::vector<engine::PhantomNodeWithDistance>
NearestPhantomNodesInRange(const util::Coordinate /*input_coordinate*/, NearestPhantomNodes(const util::Coordinate /*input_coordinate*/,
const float /*max_distance*/, const size_t /*max_results*/,
const Approach /*approach*/, const boost::optional<double> /*max_distance*/,
const boost::optional<engine::Bearing> /*bearing*/,
const engine::Approach /*approach*/) const override
{
return {};
};
engine::PhantomCandidateAlternatives NearestCandidatesWithAlternativeFromBigComponent(
const util::Coordinate /*input_coordinate*/,
const boost::optional<double> /*max_distance*/,
const boost::optional<engine::Bearing> /*bearing*/,
const engine::Approach /*approach*/,
const bool /*use_all_edges*/) const override const bool /*use_all_edges*/) const override
{ {
return {}; return {};
} };
std::vector<PhantomNodeWithDistance>
NearestPhantomNodes(const util::Coordinate /*input_coordinate*/,
const unsigned /*max_results*/,
const double /*max_distance*/,
const int /*bearing*/,
const int /*bearing_range*/,
const Approach /*approach*/) const override
{
return {};
}
std::vector<PhantomNodeWithDistance>
NearestPhantomNodes(const util::Coordinate /*input_coordinate*/,
const unsigned /*max_results*/,
const int /*bearing*/,
const int /*bearing_range*/,
const Approach /*approach*/) const override
{
return {};
}
std::vector<PhantomNodeWithDistance>
NearestPhantomNodes(const util::Coordinate /*input_coordinate*/,
const unsigned /*max_results*/,
const Approach /*approach*/) const override
{
return {};
}
std::vector<PhantomNodeWithDistance>
NearestPhantomNodes(const util::Coordinate /*input_coordinate*/,
const unsigned /*max_results*/,
const double /*max_distance*/,
const Approach /*approach*/) const override
{
return {};
}
std::pair<PhantomNode, PhantomNode>
NearestPhantomNodeWithAlternativeFromBigComponent(const util::Coordinate /*input_coordinate*/,
const Approach /*approach*/,
const bool /* use_all_edges */) const override
{
return {};
}
std::pair<PhantomNode, PhantomNode>
NearestPhantomNodeWithAlternativeFromBigComponent(const util::Coordinate /*input_coordinate*/,
const double /*max_distance*/,
const Approach /*approach*/,
const bool /* use_all_edges */) const override
{
return {};
}
std::pair<PhantomNode, PhantomNode>
NearestPhantomNodeWithAlternativeFromBigComponent(const util::Coordinate /*input_coordinate*/,
const double /*max_distance*/,
const int /*bearing*/,
const int /*bearing_range*/,
const Approach /*approach*/,
const bool /* use_all_edges */) const override
{
return {};
}
std::pair<PhantomNode, PhantomNode>
NearestPhantomNodeWithAlternativeFromBigComponent(const util::Coordinate /*input_coordinate*/,
const int /*bearing*/,
const int /*bearing_range*/,
const Approach /*approach*/,
const bool /* use_all_edges */) const override
{
return {};
}
util::guidance::LaneTupleIdPair GetLaneData(const EdgeID /*id*/) const override util::guidance::LaneTupleIdPair GetLaneData(const EdgeID /*id*/) const override
{ {
@ -394,15 +328,16 @@ namespace routing_algorithms
namespace offline namespace offline
{ {
template <typename PhantomT>
inline void search(SearchEngineData<Algorithm> &engine_working_data, inline void search(SearchEngineData<Algorithm> &engine_working_data,
const datafacade::ContiguousInternalMemoryDataFacade<Algorithm> &facade, const datafacade::ContiguousInternalMemoryDataFacade<Algorithm> &facade,
typename SearchEngineData<Algorithm>::QueryHeap &forward_heap, typename SearchEngineData<Algorithm>::QueryHeap &forward_heap,
typename SearchEngineData<Algorithm>::QueryHeap &reverse_heap, typename SearchEngineData<Algorithm>::QueryHeap &reverse_heap,
EdgeWeight &weight, EdgeWeight &weight,
std::vector<NodeID> &packed_leg, std::vector<NodeID> &packed_leg,
const bool force_loop_forward, const std::vector<NodeID> &forward_loop_nodes,
const bool force_loop_reverse, const std::vector<NodeID> &reverse_loop_nodes,
const PhantomNodes &phantom_nodes, const PhantomT &endpoints,
const EdgeWeight weight_upper_bound = INVALID_EDGE_WEIGHT) const EdgeWeight weight_upper_bound = INVALID_EDGE_WEIGHT)
{ {
mld::search(engine_working_data, mld::search(engine_working_data,
@ -411,9 +346,9 @@ inline void search(SearchEngineData<Algorithm> &engine_working_data,
reverse_heap, reverse_heap,
weight, weight,
packed_leg, packed_leg,
force_loop_forward, forward_loop_nodes,
force_loop_reverse, reverse_loop_nodes,
phantom_nodes, endpoints,
weight_upper_bound); weight_upper_bound);
} }
@ -421,10 +356,10 @@ template <typename RandomIter, typename FacadeT>
void unpackPath(const FacadeT &facade, void unpackPath(const FacadeT &facade,
RandomIter packed_path_begin, RandomIter packed_path_begin,
RandomIter packed_path_end, RandomIter packed_path_end,
const PhantomNodes &phantom_nodes, const PhantomEndpoints &endpoints,
std::vector<PathData> &unpacked_path) std::vector<PathData> &unpacked_path)
{ {
mld::unpackPath(facade, packed_path_begin, packed_path_end, phantom_nodes, unpacked_path); mld::unpackPath(facade, packed_path_begin, packed_path_end, endpoints, unpacked_path);
} }
} // namespace offline } // namespace offline
@ -442,11 +377,12 @@ BOOST_AUTO_TEST_CASE(shortest_path)
osrm::engine::SearchEngineData<Algorithm> heaps; osrm::engine::SearchEngineData<Algorithm> heaps;
osrm::engine::datafacade::ContiguousInternalMemoryDataFacade<Algorithm> facade; osrm::engine::datafacade::ContiguousInternalMemoryDataFacade<Algorithm> facade;
std::vector<osrm::engine::PhantomNodes> phantom_nodes; std::vector<osrm::engine::PhantomNodeCandidates> waypoints;
phantom_nodes.push_back({osrm::engine::PhantomNode{}, osrm::engine::PhantomNode{}}); waypoints.push_back({osrm::engine::PhantomNode{}});
waypoints.push_back({osrm::engine::PhantomNode{}});
auto route = auto route =
osrm::engine::routing_algorithms::shortestPathSearch(heaps, facade, phantom_nodes, false); osrm::engine::routing_algorithms::shortestPathSearch(heaps, facade, waypoints, false);
BOOST_CHECK_EQUAL(route.shortest_path_weight, INVALID_EDGE_WEIGHT); BOOST_CHECK_EQUAL(route.shortest_path_weight, INVALID_EDGE_WEIGHT);
} }

View File

@ -110,99 +110,33 @@ class MockBaseDataFacade : public engine::datafacade::BaseDataFacade
std::vector<engine::PhantomNodeWithDistance> std::vector<engine::PhantomNodeWithDistance>
NearestPhantomNodesInRange(const util::Coordinate /*input_coordinate*/, NearestPhantomNodesInRange(const util::Coordinate /*input_coordinate*/,
const float /*max_distance*/, const double /*max_distance*/,
const int /*bearing*/, const boost::optional<engine::Bearing> /*bearing*/,
const int /*bearing_range*/,
const engine::Approach /*approach*/, const engine::Approach /*approach*/,
const bool /*use_all_edges*/) const override const bool /*use_all_edges*/) const override
{ {
return {}; return {};
} };
std::vector<engine::PhantomNodeWithDistance> std::vector<engine::PhantomNodeWithDistance>
NearestPhantomNodesInRange(const util::Coordinate /*input_coordinate*/, NearestPhantomNodes(const util::Coordinate /*input_coordinate*/,
const float /*max_distance*/, const size_t /*max_results*/,
const boost::optional<double> /*max_distance*/,
const boost::optional<engine::Bearing> /*bearing*/,
const engine::Approach /*approach*/) const override
{
return {};
};
engine::PhantomCandidateAlternatives NearestCandidatesWithAlternativeFromBigComponent(
const util::Coordinate /*input_coordinate*/,
const boost::optional<double> /*max_distance*/,
const boost::optional<engine::Bearing> /*bearing*/,
const engine::Approach /*approach*/, const engine::Approach /*approach*/,
const bool /*use_all_edges*/) const override const bool /*use_all_edges*/) const override
{ {
return {}; return {};
} };
std::vector<engine::PhantomNodeWithDistance>
NearestPhantomNodes(const util::Coordinate /*input_coordinate*/,
const unsigned /*max_results*/,
const double /*max_distance*/,
const int /*bearing*/,
const int /*bearing_range*/,
const engine::Approach /*approach*/) const override
{
return {};
}
std::vector<engine::PhantomNodeWithDistance>
NearestPhantomNodes(const util::Coordinate /*input_coordinate*/,
const unsigned /*max_results*/,
const int /*bearing*/,
const int /*bearing_range*/,
const engine::Approach /*approach*/) const override
{
return {};
}
std::vector<engine::PhantomNodeWithDistance>
NearestPhantomNodes(const util::Coordinate /*input_coordinate*/,
const unsigned /*max_results*/,
const engine::Approach /*approach*/) const override
{
return {};
}
std::vector<engine::PhantomNodeWithDistance>
NearestPhantomNodes(const util::Coordinate /*input_coordinate*/,
const unsigned /*max_results*/,
const double /*max_distance*/,
const engine::Approach /*approach*/) const override
{
return {};
}
std::pair<engine::PhantomNode, engine::PhantomNode>
NearestPhantomNodeWithAlternativeFromBigComponent(const util::Coordinate /*input_coordinate*/,
const engine::Approach /*approach*/,
const bool /* use_all_edges */) const override
{
return {};
}
std::pair<engine::PhantomNode, engine::PhantomNode>
NearestPhantomNodeWithAlternativeFromBigComponent(const util::Coordinate /*input_coordinate*/,
const double /*max_distance*/,
const engine::Approach /*approach*/,
const bool /* use_all_edges */) const override
{
return {};
}
std::pair<engine::PhantomNode, engine::PhantomNode>
NearestPhantomNodeWithAlternativeFromBigComponent(const util::Coordinate /*input_coordinate*/,
const double /*max_distance*/,
const int /*bearing*/,
const int /*bearing_range*/,
const engine::Approach /*approach*/,
const bool /* use_all_edges */) const override
{
return {};
}
std::pair<engine::PhantomNode, engine::PhantomNode>
NearestPhantomNodeWithAlternativeFromBigComponent(const util::Coordinate /*input_coordinate*/,
const int /*bearing*/,
const int /*bearing_range*/,
const engine::Approach /*approach*/,
const bool /* use_all_edges */) const override
{
return {};
}
std::uint32_t GetCheckSum() const override { return 0; } std::uint32_t GetCheckSum() const override { return 0; }

View File

@ -19,6 +19,20 @@
#define CHECK_EQUAL_RANGE(R1, R2) \ #define CHECK_EQUAL_RANGE(R1, R2) \
BOOST_CHECK_EQUAL_COLLECTIONS((R1).begin(), (R1).end(), (R2).begin(), (R2).end()); BOOST_CHECK_EQUAL_COLLECTIONS((R1).begin(), (R1).end(), (R2).begin(), (R2).end());
#define CHECK_EQUAL_RANGE_OF_HINTS(R1, R2) \
BOOST_REQUIRE_EQUAL((R1).size(), (R2).size()); \
for (const auto i : util::irange<std::size_t>(0UL, (R1).size())) \
{ \
BOOST_REQUIRE(((R1)[i] && (R2)[i]) || !((R1)[i] || (R2)[i])); \
if ((R1)[i]) \
{ \
BOOST_CHECK_EQUAL_COLLECTIONS((R1)[i]->segment_hints.begin(), \
(R1)[i]->segment_hints.end(), \
(R2)[i]->segment_hints.begin(), \
(R2)[i]->segment_hints.end()); \
} \
}
BOOST_AUTO_TEST_SUITE(api_parameters_parser) BOOST_AUTO_TEST_SUITE(api_parameters_parser)
using namespace osrm; using namespace osrm;
@ -117,15 +131,16 @@ BOOST_AUTO_TEST_CASE(invalid_table_urls)
// BOOST_CHECK_EQUAL(testInvalidOptions<TableParameters>("1,2;3,4?destinations=2"), 7UL); // BOOST_CHECK_EQUAL(testInvalidOptions<TableParameters>("1,2;3,4?destinations=2"), 7UL);
} }
BOOST_AUTO_TEST_CASE(valid_route_hint) BOOST_AUTO_TEST_CASE(valid_route_segment_hint)
{ {
engine::PhantomNode reference_node; engine::PhantomNode reference_node;
reference_node.input_location = reference_node.input_location =
util::Coordinate(util::FloatLongitude{7.432251}, util::FloatLatitude{43.745995}); util::Coordinate(util::FloatLongitude{7.432251}, util::FloatLatitude{43.745995});
engine::Hint reference_hint{reference_node, 0x1337}; engine::SegmentHint reference_segment_hint{reference_node, 0x1337};
auto encoded_hint = reference_hint.ToBase64(); auto encoded_hint = reference_segment_hint.ToBase64();
auto hint = engine::Hint::FromBase64(encoded_hint); auto seg_hint = engine::SegmentHint::FromBase64(encoded_hint);
BOOST_CHECK_EQUAL(hint.phantom.input_location, reference_hint.phantom.input_location); BOOST_CHECK_EQUAL(seg_hint.phantom.input_location,
reference_segment_hint.phantom.input_location);
} }
BOOST_AUTO_TEST_CASE(valid_route_urls) BOOST_AUTO_TEST_CASE(valid_route_urls)
@ -147,7 +162,7 @@ BOOST_AUTO_TEST_CASE(valid_route_urls)
CHECK_EQUAL_RANGE(reference_1.radiuses, result_1->radiuses); CHECK_EQUAL_RANGE(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);
CHECK_EQUAL_RANGE(reference_1.hints, result_1->hints); CHECK_EQUAL_RANGE_OF_HINTS(reference_1.hints, result_1->hints);
RouteParameters reference_2{}; RouteParameters reference_2{};
reference_2.alternatives = true; reference_2.alternatives = true;
@ -170,7 +185,7 @@ BOOST_AUTO_TEST_CASE(valid_route_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);
CHECK_EQUAL_RANGE(reference_2.hints, result_2->hints); CHECK_EQUAL_RANGE_OF_HINTS(reference_2.hints, result_2->hints);
BOOST_CHECK_EQUAL(result_2->annotations_type == RouteParameters::AnnotationsType::All, true); BOOST_CHECK_EQUAL(result_2->annotations_type == RouteParameters::AnnotationsType::All, true);
RouteParameters reference_3{false, RouteParameters reference_3{false,
@ -195,14 +210,15 @@ BOOST_AUTO_TEST_CASE(valid_route_urls)
CHECK_EQUAL_RANGE(reference_3.radiuses, result_3->radiuses); CHECK_EQUAL_RANGE(reference_3.radiuses, result_3->radiuses);
CHECK_EQUAL_RANGE(reference_3.approaches, result_3->approaches); CHECK_EQUAL_RANGE(reference_3.approaches, result_3->approaches);
CHECK_EQUAL_RANGE(reference_3.coordinates, result_3->coordinates); CHECK_EQUAL_RANGE(reference_3.coordinates, result_3->coordinates);
CHECK_EQUAL_RANGE(reference_3.hints, result_3->hints); CHECK_EQUAL_RANGE_OF_HINTS(reference_3.hints, result_3->hints);
engine::PhantomNode phantom_1; engine::PhantomNode phantom_1;
phantom_1.input_location = coords_1[0]; phantom_1.input_location = coords_1[0];
engine::PhantomNode phantom_2; engine::PhantomNode phantom_2;
phantom_2.input_location = coords_1[1]; phantom_2.input_location = coords_1[1];
std::vector<boost::optional<engine::Hint>> hints_4 = {engine::Hint{phantom_1, 0x1337}, std::vector<boost::optional<engine::Hint>> hints_4 = {
engine::Hint{phantom_2, 0x1337}}; engine::Hint{{engine::SegmentHint{phantom_1, 0x1337}}},
engine::Hint{{engine::SegmentHint{phantom_2, 0x1337}}}};
RouteParameters reference_4{false, RouteParameters reference_4{false,
false, false,
false, false,
@ -226,7 +242,7 @@ BOOST_AUTO_TEST_CASE(valid_route_urls)
CHECK_EQUAL_RANGE(reference_4.radiuses, result_4->radiuses); CHECK_EQUAL_RANGE(reference_4.radiuses, result_4->radiuses);
CHECK_EQUAL_RANGE(reference_4.approaches, result_4->approaches); CHECK_EQUAL_RANGE(reference_4.approaches, result_4->approaches);
CHECK_EQUAL_RANGE(reference_4.coordinates, result_4->coordinates); CHECK_EQUAL_RANGE(reference_4.coordinates, result_4->coordinates);
CHECK_EQUAL_RANGE(reference_4.hints, result_4->hints); CHECK_EQUAL_RANGE_OF_HINTS(reference_4.hints, result_4->hints);
std::vector<boost::optional<engine::Bearing>> bearings_4 = { std::vector<boost::optional<engine::Bearing>> bearings_4 = {
boost::none, boost::none,
@ -255,7 +271,7 @@ BOOST_AUTO_TEST_CASE(valid_route_urls)
CHECK_EQUAL_RANGE(reference_5.radiuses, result_5->radiuses); CHECK_EQUAL_RANGE(reference_5.radiuses, result_5->radiuses);
CHECK_EQUAL_RANGE(reference_5.approaches, result_5->approaches); CHECK_EQUAL_RANGE(reference_5.approaches, result_5->approaches);
CHECK_EQUAL_RANGE(reference_5.coordinates, result_5->coordinates); CHECK_EQUAL_RANGE(reference_5.coordinates, result_5->coordinates);
CHECK_EQUAL_RANGE(reference_5.hints, result_5->hints); CHECK_EQUAL_RANGE_OF_HINTS(reference_5.hints, result_5->hints);
std::vector<util::Coordinate> coords_2 = {{util::FloatLongitude{0}, util::FloatLatitude{1}}, std::vector<util::Coordinate> coords_2 = {{util::FloatLongitude{0}, util::FloatLatitude{1}},
{util::FloatLongitude{2}, util::FloatLatitude{3}}, {util::FloatLongitude{2}, util::FloatLatitude{3}},
@ -275,7 +291,7 @@ BOOST_AUTO_TEST_CASE(valid_route_urls)
CHECK_EQUAL_RANGE(reference_6.radiuses, result_6->radiuses); CHECK_EQUAL_RANGE(reference_6.radiuses, result_6->radiuses);
CHECK_EQUAL_RANGE(reference_6.approaches, result_6->approaches); CHECK_EQUAL_RANGE(reference_6.approaches, result_6->approaches);
CHECK_EQUAL_RANGE(reference_6.coordinates, result_6->coordinates); CHECK_EQUAL_RANGE(reference_6.coordinates, result_6->coordinates);
CHECK_EQUAL_RANGE(reference_6.hints, result_6->hints); CHECK_EQUAL_RANGE_OF_HINTS(reference_6.hints, result_6->hints);
auto result_7 = parseParameters<RouteParameters>("1,2;3,4?radiuses=;unlimited"); auto result_7 = parseParameters<RouteParameters>("1,2;3,4?radiuses=;unlimited");
RouteParameters reference_7{}; RouteParameters reference_7{};
@ -293,7 +309,7 @@ BOOST_AUTO_TEST_CASE(valid_route_urls)
CHECK_EQUAL_RANGE(reference_7.radiuses, result_7->radiuses); CHECK_EQUAL_RANGE(reference_7.radiuses, result_7->radiuses);
CHECK_EQUAL_RANGE(reference_7.approaches, result_7->approaches); CHECK_EQUAL_RANGE(reference_7.approaches, result_7->approaches);
CHECK_EQUAL_RANGE(reference_7.coordinates, result_7->coordinates); CHECK_EQUAL_RANGE(reference_7.coordinates, result_7->coordinates);
CHECK_EQUAL_RANGE(reference_7.hints, result_7->hints); CHECK_EQUAL_RANGE_OF_HINTS(reference_7.hints, result_7->hints);
auto result_8 = parseParameters<RouteParameters>("1,2;3,4?radiuses=;"); auto result_8 = parseParameters<RouteParameters>("1,2;3,4?radiuses=;");
RouteParameters reference_8{}; RouteParameters reference_8{};
@ -320,7 +336,10 @@ BOOST_AUTO_TEST_CASE(valid_route_urls)
engine::PhantomNode phantom_4; engine::PhantomNode phantom_4;
phantom_4.input_location = coords_3[2]; phantom_4.input_location = coords_3[2];
std::vector<boost::optional<engine::Hint>> hints_10 = { std::vector<boost::optional<engine::Hint>> hints_10 = {
engine::Hint{phantom_3, 0x1337}, boost::none, engine::Hint{phantom_4, 0x1337}, boost::none}; engine::Hint{{engine::SegmentHint{phantom_3, 0x1337}}},
{},
engine::Hint{{engine::SegmentHint{phantom_4, 0x1337}}},
{}};
RouteParameters reference_10{false, RouteParameters reference_10{false,
false, false,
@ -346,7 +365,7 @@ BOOST_AUTO_TEST_CASE(valid_route_urls)
CHECK_EQUAL_RANGE(reference_10.radiuses, result_10->radiuses); CHECK_EQUAL_RANGE(reference_10.radiuses, result_10->radiuses);
CHECK_EQUAL_RANGE(reference_10.approaches, result_10->approaches); CHECK_EQUAL_RANGE(reference_10.approaches, result_10->approaches);
CHECK_EQUAL_RANGE(reference_10.coordinates, result_10->coordinates); CHECK_EQUAL_RANGE(reference_10.coordinates, result_10->coordinates);
CHECK_EQUAL_RANGE(reference_10.hints, result_10->hints); CHECK_EQUAL_RANGE_OF_HINTS(reference_10.hints, result_10->hints);
// Do not generate Hints when they are explicitly disabled // Do not generate Hints when they are explicitly disabled
auto result_11 = parseParameters<RouteParameters>("1,2;3,4?generate_hints=false"); auto result_11 = parseParameters<RouteParameters>("1,2;3,4?generate_hints=false");
@ -459,7 +478,7 @@ BOOST_AUTO_TEST_CASE(valid_route_urls)
CHECK_EQUAL_RANGE(reference_18.radiuses, result_18->radiuses); CHECK_EQUAL_RANGE(reference_18.radiuses, result_18->radiuses);
CHECK_EQUAL_RANGE(reference_18.approaches, result_18->approaches); CHECK_EQUAL_RANGE(reference_18.approaches, result_18->approaches);
CHECK_EQUAL_RANGE(reference_18.coordinates, result_18->coordinates); CHECK_EQUAL_RANGE(reference_18.coordinates, result_18->coordinates);
CHECK_EQUAL_RANGE(reference_18.hints, result_18->hints); CHECK_EQUAL_RANGE_OF_HINTS(reference_18.hints, result_18->hints);
RouteParameters reference_19{}; RouteParameters reference_19{};
reference_19.alternatives = true; reference_19.alternatives = true;
@ -478,7 +497,7 @@ BOOST_AUTO_TEST_CASE(valid_route_urls)
CHECK_EQUAL_RANGE(reference_19.radiuses, result_19->radiuses); CHECK_EQUAL_RANGE(reference_19.radiuses, result_19->radiuses);
CHECK_EQUAL_RANGE(reference_19.approaches, result_19->approaches); CHECK_EQUAL_RANGE(reference_19.approaches, result_19->approaches);
CHECK_EQUAL_RANGE(reference_19.coordinates, result_19->coordinates); CHECK_EQUAL_RANGE(reference_19.coordinates, result_19->coordinates);
CHECK_EQUAL_RANGE(reference_19.hints, result_19->hints); CHECK_EQUAL_RANGE_OF_HINTS(reference_19.hints, result_19->hints);
RouteParameters reference_20{}; RouteParameters reference_20{};
reference_20.alternatives = false; reference_20.alternatives = false;
@ -497,7 +516,7 @@ BOOST_AUTO_TEST_CASE(valid_route_urls)
CHECK_EQUAL_RANGE(reference_20.radiuses, result_20->radiuses); CHECK_EQUAL_RANGE(reference_20.radiuses, result_20->radiuses);
CHECK_EQUAL_RANGE(reference_20.approaches, result_20->approaches); CHECK_EQUAL_RANGE(reference_20.approaches, result_20->approaches);
CHECK_EQUAL_RANGE(reference_20.coordinates, result_20->coordinates); CHECK_EQUAL_RANGE(reference_20.coordinates, result_20->coordinates);
CHECK_EQUAL_RANGE(reference_20.hints, result_20->hints); CHECK_EQUAL_RANGE_OF_HINTS(reference_20.hints, result_20->hints);
// exclude flags // exclude flags
RouteParameters reference_21{}; RouteParameters reference_21{};
@ -516,7 +535,7 @@ BOOST_AUTO_TEST_CASE(valid_route_urls)
CHECK_EQUAL_RANGE(reference_21.radiuses, result_21->radiuses); CHECK_EQUAL_RANGE(reference_21.radiuses, result_21->radiuses);
CHECK_EQUAL_RANGE(reference_21.approaches, result_21->approaches); CHECK_EQUAL_RANGE(reference_21.approaches, result_21->approaches);
CHECK_EQUAL_RANGE(reference_21.coordinates, result_21->coordinates); CHECK_EQUAL_RANGE(reference_21.coordinates, result_21->coordinates);
CHECK_EQUAL_RANGE(reference_21.hints, result_21->hints); CHECK_EQUAL_RANGE_OF_HINTS(reference_21.hints, result_21->hints);
CHECK_EQUAL_RANGE(reference_21.exclude, result_21->exclude); CHECK_EQUAL_RANGE(reference_21.exclude, result_21->exclude);
} }

View File

@ -200,8 +200,8 @@ void simple_verify_rtree(RTreeT &rtree,
auto result_u = rtree.Nearest(pu, 1); auto result_u = rtree.Nearest(pu, 1);
auto result_v = rtree.Nearest(pv, 1); auto result_v = rtree.Nearest(pv, 1);
BOOST_CHECK(result_u.size() == 1 && result_v.size() == 1); BOOST_CHECK(result_u.size() == 1 && result_v.size() == 1);
BOOST_CHECK(result_u.front().u == e.u || result_u.front().v == e.u); BOOST_CHECK(result_u.front().data.u == e.u || result_u.front().data.v == e.u);
BOOST_CHECK(result_v.front().u == e.v || result_v.front().v == e.v); BOOST_CHECK(result_v.front().data.u == e.v || result_v.front().data.v == e.v);
} }
} }
@ -226,8 +226,8 @@ void sampling_verify_rtree(RTreeT &rtree,
auto result_lsnn = lsnn.Nearest(q, 1); auto result_lsnn = lsnn.Nearest(q, 1);
BOOST_CHECK(result_rtree.size() == 1); BOOST_CHECK(result_rtree.size() == 1);
BOOST_CHECK(result_lsnn.size() == 1); BOOST_CHECK(result_lsnn.size() == 1);
auto rtree_u = result_rtree.back().u; auto rtree_u = result_rtree.back().data.u;
auto rtree_v = result_rtree.back().v; auto rtree_v = result_rtree.back().data.v;
auto lsnn_u = result_lsnn.back().u; auto lsnn_u = result_lsnn.back().u;
auto lsnn_v = result_lsnn.back().v; auto lsnn_v = result_lsnn.back().v;
@ -322,8 +322,8 @@ BOOST_AUTO_TEST_CASE(regression_test)
BOOST_CHECK(result_rtree.size() == 1); BOOST_CHECK(result_rtree.size() == 1);
BOOST_CHECK(result_ls.size() == 1); BOOST_CHECK(result_ls.size() == 1);
BOOST_CHECK_EQUAL(result_ls.front().u, result_rtree.front().u); BOOST_CHECK_EQUAL(result_ls.front().u, result_rtree.front().data.u);
BOOST_CHECK_EQUAL(result_ls.front().v, result_rtree.front().v); BOOST_CHECK_EQUAL(result_ls.front().v, result_rtree.front().data.v);
} }
// Bug: If you querry a point with a narrow radius, no result should be returned // Bug: If you querry a point with a narrow radius, no result should be returned
@ -347,8 +347,8 @@ BOOST_AUTO_TEST_CASE(radius_regression_test)
Coordinate input(FloatLongitude{5.2}, FloatLatitude{5.0}); Coordinate input(FloatLongitude{5.2}, FloatLatitude{5.0});
{ {
auto results = query.NearestPhantomNodesInRange( auto results = query.NearestPhantomNodes(
input, 0.01, osrm::engine::Approach::UNRESTRICTED, true); input, osrm::engine::Approach::UNRESTRICTED, boost::none, 0.01, boost::none, true);
BOOST_CHECK_EQUAL(results.size(), 0); BOOST_CHECK_EQUAL(results.size(), 0);
} }
} }
@ -373,14 +373,14 @@ BOOST_AUTO_TEST_CASE(permissive_edge_snapping)
Coordinate input(FloatLongitude{0.0005}, FloatLatitude{0.0005}); Coordinate input(FloatLongitude{0.0005}, FloatLatitude{0.0005});
{ {
auto results = query.NearestPhantomNodesInRange( auto results = query.NearestPhantomNodes(
input, 1000, osrm::engine::Approach::UNRESTRICTED, false); input, osrm::engine::Approach::UNRESTRICTED, boost::none, 1000, boost::none, false);
BOOST_CHECK_EQUAL(results.size(), 1); BOOST_CHECK_EQUAL(results.size(), 1);
} }
{ {
auto results = query.NearestPhantomNodesInRange( auto results = query.NearestPhantomNodes(
input, 1000, osrm::engine::Approach::UNRESTRICTED, true); input, osrm::engine::Approach::UNRESTRICTED, boost::none, 1000, boost::none, true);
BOOST_CHECK_EQUAL(results.size(), 2); BOOST_CHECK_EQUAL(results.size(), 2);
} }
} }
@ -405,21 +405,30 @@ BOOST_AUTO_TEST_CASE(bearing_tests)
Coordinate input(FloatLongitude{5.1}, FloatLatitude{5.0}); Coordinate input(FloatLongitude{5.1}, FloatLatitude{5.0});
{ {
auto results = query.NearestPhantomNodes(input, 5, osrm::engine::Approach::UNRESTRICTED); auto results = query.NearestPhantomNodes(
input, osrm::engine::Approach::UNRESTRICTED, 5, boost::none, boost::none, false);
BOOST_CHECK_EQUAL(results.size(), 2); BOOST_CHECK_EQUAL(results.size(), 2);
BOOST_CHECK_EQUAL(results.back().phantom_node.forward_segment_id.id, 0); BOOST_CHECK_EQUAL(results.back().phantom_node.forward_segment_id.id, 0);
BOOST_CHECK_EQUAL(results.back().phantom_node.reverse_segment_id.id, 1); BOOST_CHECK_EQUAL(results.back().phantom_node.reverse_segment_id.id, 1);
} }
{ {
auto results = auto results = query.NearestPhantomNodes(input,
query.NearestPhantomNodes(input, 5, 270, 10, osrm::engine::Approach::UNRESTRICTED); osrm::engine::Approach::UNRESTRICTED,
5,
boost::none,
engine::Bearing{270, 10},
false);
BOOST_CHECK_EQUAL(results.size(), 0); BOOST_CHECK_EQUAL(results.size(), 0);
} }
{ {
auto results = auto results = query.NearestPhantomNodes(input,
query.NearestPhantomNodes(input, 5, 45, 10, osrm::engine::Approach::UNRESTRICTED); osrm::engine::Approach::UNRESTRICTED,
5,
boost::none,
engine::Bearing{45, 10},
false);
BOOST_CHECK_EQUAL(results.size(), 2); BOOST_CHECK_EQUAL(results.size(), 2);
BOOST_CHECK(results[0].phantom_node.forward_segment_id.enabled); BOOST_CHECK(results[0].phantom_node.forward_segment_id.enabled);
@ -432,20 +441,28 @@ BOOST_AUTO_TEST_CASE(bearing_tests)
} }
{ {
auto results = query.NearestPhantomNodesInRange( auto results = query.NearestPhantomNodes(
input, 11000, osrm::engine::Approach::UNRESTRICTED, true); input, osrm::engine::Approach::UNRESTRICTED, boost::none, 11000, boost::none, true);
BOOST_CHECK_EQUAL(results.size(), 2); BOOST_CHECK_EQUAL(results.size(), 2);
} }
{ {
auto results = query.NearestPhantomNodesInRange( auto results = query.NearestPhantomNodes(input,
input, 11000, 270, 10, osrm::engine::Approach::UNRESTRICTED, true); osrm::engine::Approach::UNRESTRICTED,
boost::none,
11000,
engine::Bearing{270, 10},
true);
BOOST_CHECK_EQUAL(results.size(), 0); BOOST_CHECK_EQUAL(results.size(), 0);
} }
{ {
auto results = query.NearestPhantomNodesInRange( auto results = query.NearestPhantomNodes(input,
input, 11000, 45, 10, osrm::engine::Approach::UNRESTRICTED, true); osrm::engine::Approach::UNRESTRICTED,
boost::none,
11000,
engine::Bearing{45, 10},
true);
BOOST_CHECK_EQUAL(results.size(), 2); BOOST_CHECK_EQUAL(results.size(), 2);
BOOST_CHECK(results[0].phantom_node.forward_segment_id.enabled); BOOST_CHECK(results[0].phantom_node.forward_segment_id.enabled);