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:
parent
bb18a2b428
commit
d74e7b66bd
@ -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)
|
||||
- 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)
|
||||
- ADDED: Support snapping to multiple ways at an input location. [#5953](https://github.com/Project-OSRM/osrm-backend/pull/5953)
|
||||
|
||||
# 5.26.0
|
||||
- Changes from 5.25.0
|
||||
|
@ -28,7 +28,7 @@ Feature: Bicycle - Route around alleys
|
||||
|
||||
When I route I should get
|
||||
| from | to | a:nodes | weight | # |
|
||||
| a | f | 1:2:3:6 | 200.4 | Avoids d,e,f |
|
||||
| a | e | 1:2:5 | 176.4 | Take the alley b,e if neccessary |
|
||||
| d | f | 4:1:2:3:6 | 252.6 | Avoids the alley d,e,f |
|
||||
| a | f | 1:2:3:6 | 196.2 | Avoids d,e,f |
|
||||
| a | e | 1:2:5 | 172.2 | Take the alley b,e if neccessary |
|
||||
| d | f | 4:1:2:3:6 | 248.4 | Avoids the alley d,e,f |
|
||||
|
||||
|
@ -7,10 +7,10 @@ Feature: Car - Destination only, no passing through
|
||||
Scenario: Car - Destination only street
|
||||
Given the node map
|
||||
"""
|
||||
a e
|
||||
b c d
|
||||
a e
|
||||
b1 c 2d
|
||||
|
||||
x y
|
||||
x y
|
||||
"""
|
||||
|
||||
And the ways
|
||||
@ -23,21 +23,21 @@ Feature: Car - Destination only, no passing through
|
||||
When I route I should get
|
||||
| from | to | route |
|
||||
| a | b | ab,ab |
|
||||
| a | c | ab,bcd |
|
||||
| a | d | ab,bcd,bcd |
|
||||
| a | c | ab,bcd,bcd |
|
||||
| a | 2 | ab,bcd,bcd |
|
||||
| a | e | axye,axye |
|
||||
| e | d | de,de |
|
||||
| e | c | de,bcd |
|
||||
| e | b | de,bcd,bcd |
|
||||
| e | c | de,bcd,bcd |
|
||||
| e | 1 | de,bcd,bcd |
|
||||
| e | a | axye,axye |
|
||||
|
||||
Scenario: Car - Destination only street
|
||||
Given the node map
|
||||
"""
|
||||
a e
|
||||
b c d
|
||||
a e
|
||||
b1 c 2d
|
||||
|
||||
x y
|
||||
x y
|
||||
"""
|
||||
|
||||
And the ways
|
||||
@ -51,12 +51,12 @@ Feature: Car - Destination only, no passing through
|
||||
When I route I should get
|
||||
| from | to | route |
|
||||
| a | b | ab,ab |
|
||||
| a | c | ab,bc |
|
||||
| a | d | ab,cd |
|
||||
| a | c | ab,bc,bc |
|
||||
| a | 2 | ab,bc,cd |
|
||||
| a | e | axye,axye |
|
||||
| e | d | de,de |
|
||||
| e | c | de,cd |
|
||||
| e | b | de,bc |
|
||||
| e | c | de,cd,cd |
|
||||
| e | 1 | de,cd,bc |
|
||||
| e | a | axye,axye |
|
||||
|
||||
Scenario: Car - Routing inside a destination only area
|
||||
@ -117,6 +117,7 @@ Feature: Car - Destination only, no passing through
|
||||
+ \
|
||||
+ |
|
||||
d |
|
||||
1 |
|
||||
\___e
|
||||
"""
|
||||
|
||||
@ -129,7 +130,7 @@ Feature: Car - Destination only, no passing through
|
||||
When I route I should get
|
||||
| from | to | route |
|
||||
| e | a | acbe,acbe |
|
||||
| d | a | de,acbe,acbe |
|
||||
| 1 | a | de,acbe,acbe |
|
||||
| c | d | cd,cd |
|
||||
|
||||
Scenario: Car - Routing through a parking lot tagged access=destination,service
|
||||
|
@ -411,7 +411,7 @@ Feature: Car - Turn restrictions
|
||||
y
|
||||
i j f b x a e g h
|
||||
|
||||
c d
|
||||
c1 d
|
||||
"""
|
||||
|
||||
And the ways
|
||||
@ -438,7 +438,7 @@ Feature: Car - Turn restrictions
|
||||
When I route I should get
|
||||
| from | to | route |
|
||||
| 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 |
|
||||
|
||||
@except
|
||||
|
@ -332,10 +332,11 @@ Feature: Merge Segregated Roads
|
||||
|
|
||||
.b.
|
||||
c h
|
||||
1 |
|
||||
| 4
|
||||
| |
|
||||
| |
|
||||
1 2
|
||||
| |
|
||||
2 |
|
||||
| 3
|
||||
d g
|
||||
'e'
|
||||
|
|
||||
@ -354,13 +355,13 @@ Feature: Merge Segregated Roads
|
||||
| hb | road | yes |
|
||||
|
||||
When I route I should get
|
||||
| waypoints | turns | route | intersections |
|
||||
| waypoints | turns | route | intersections |
|
||||
| a,f | depart,arrive | road,road | true:180,false:0 true:180,false:0 true:180;true:0 |
|
||||
| c,f | depart,arrive | bridge,road | true:180,false:0 true:180;true:0 |
|
||||
| 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 |
|
||||
| g,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 |
|
||||
| 3,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
|
||||
Scenario: Traffic Circle
|
||||
|
@ -67,10 +67,10 @@ Feature: Compass bearing
|
||||
Scenario: Bearing in a roundabout
|
||||
Given the node map
|
||||
"""
|
||||
k d c j
|
||||
e b
|
||||
f a
|
||||
l g h i
|
||||
k d 1c j
|
||||
e b
|
||||
f a
|
||||
l g2 h i
|
||||
"""
|
||||
|
||||
And the ways
|
||||
@ -94,8 +94,8 @@ Feature: Compass bearing
|
||||
|
||||
When I route I should get
|
||||
| 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 |
|
||||
| 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 |
|
||||
| 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 |
|
||||
| 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
|
||||
Given the node map
|
||||
|
@ -589,12 +589,12 @@ Feature: Basic Distance Matrix
|
||||
|
||||
When I request a travel distance matrix I should get
|
||||
| | a | b | c | d | e | f |
|
||||
| a | 0 | 100 | 300 | 650 | 1934.5 | 1534.6 |
|
||||
| b | 760.6 | 0 | 200 | 550.1 | 1834.6 | 1434.6 |
|
||||
| c | 560.6 | 660.5 | 0 | 350 | 1634.6 | 1234.6 |
|
||||
| d | 1484.6 | 1584.5| 1784.5 | 0 | 1284.5 | 884.6 |
|
||||
| e | 200 | 300 | 500 | 710.6 | 0 | 1595.2 |
|
||||
| f | 600 | 699.9 | 899.9 | 1110.5 | 399.9 | 0 |
|
||||
| a | 0 | 100 | 300 | 650 | 660.5 | 1534.6 |
|
||||
| b | 760.6 | 0 | 200 | 550.1 | 560.6 | 1434.6 |
|
||||
| c | 560.6 | 660.5 | 0 | 350 | 360.5 | 1234.6 |
|
||||
| d | 1484.6 | 1584.5| 1645.1 | 0 | 1284.5 | 884.6 |
|
||||
| e | 200 | 300 | 360.5 | 710.6 | 0 | 1595.2 |
|
||||
| f | 600 | 699.9 | 760.5 | 884.6 | 399.9 | 0 |
|
||||
|
||||
|
||||
Scenario: Testbot - Filling in noroutes with estimates (defaults to input coordinate location)
|
||||
@ -720,11 +720,10 @@ Feature: Basic Distance Matrix
|
||||
| 1 | 2 | abcdef,fghij,fghij | 1000.1m |
|
||||
| 1 | 3 | abcdef,fghij,fghij | 1400.1m |
|
||||
| 2 | 3 | fghij,fghij | 400m |
|
||||
|
||||
|
||||
|
||||
When I request a travel distance matrix I should get
|
||||
| | 1 | 2 | 3 |
|
||||
| | 1 | 2 | 3 |
|
||||
| 1 | 0 | 1000.1 | 1400.1 |
|
||||
| 2 | 1000.1 | 0 | 400 |
|
||||
| 3 | 1400.1 | 400 | 0 |
|
||||
|
||||
|
@ -491,18 +491,18 @@ Feature: Basic Duration Matrix
|
||||
|
||||
When I route I should get
|
||||
| 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
|
||||
| | a | b | c | d |
|
||||
| a | 0 | 1 | 5 | 10 |
|
||||
| | a | b | c | d |
|
||||
| a | 0 | 1 | 1 | 6 |
|
||||
|
||||
When I request a travel time matrix I should get
|
||||
| | a |
|
||||
| a | 0 |
|
||||
| b | 1 |
|
||||
| c | 15 |
|
||||
| d | 10 |
|
||||
| c | 1 |
|
||||
| d | 6 |
|
||||
|
||||
Scenario: Testbot - OneToMany vs ManyToOne
|
||||
Given the node map
|
||||
|
629
features/testbot/snap_intersection.feature
Normal file
629
features/testbot/snap_intersection.feature
Normal 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 |
|
@ -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 |
|
||||
| b | f | bc,cf,cf | 36 km/h | 40s +-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 |
|
||||
|
||||
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 |
|
||||
| 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 |
|
||||
| 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 |
|
||||
|
@ -281,7 +281,7 @@ Feature: Weight tests
|
||||
|
||||
When I route I should get
|
||||
| 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 |
|
||||
| e,a | ,, | 60m +-.1 | 2.21,2.22,0 | 10s,200s,0s |
|
||||
| e,d | ,, | 40m +-.1 | 4.01,1.11,0 | 190s,100s,0s |
|
||||
|
@ -9,9 +9,12 @@
|
||||
#include "engine/hint.hpp"
|
||||
#include "util/coordinate_calculation.hpp"
|
||||
|
||||
#include <boost/algorithm/string/join.hpp>
|
||||
#include <boost/assert.hpp>
|
||||
#include <boost/range/adaptor/transformed.hpp>
|
||||
#include <boost/range/algorithm/transform.hpp>
|
||||
|
||||
#include <boost/range/adaptor/filtered.hpp>
|
||||
#include <memory>
|
||||
#include <vector>
|
||||
|
||||
@ -22,6 +25,8 @@ namespace engine
|
||||
namespace api
|
||||
{
|
||||
|
||||
static const constexpr char *INTERSECTION_DELIMITER = " / ";
|
||||
|
||||
class BaseAPI
|
||||
{
|
||||
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() == segment_end_coordinates.size() + 1);
|
||||
BOOST_ASSERT(parameters.coordinates.size() == waypoint_candidates.size());
|
||||
|
||||
util::json::Array waypoints;
|
||||
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(
|
||||
segment_end_coordinates, out_iter, [this](const PhantomNodes &phantom_pair) {
|
||||
return MakeWaypoint(phantom_pair.target_phantom);
|
||||
});
|
||||
waypoint_candidates,
|
||||
waypoints.values.begin(),
|
||||
[this](const PhantomNodeCandidates &candidates) { return MakeWaypoint(candidates); });
|
||||
return waypoints;
|
||||
}
|
||||
|
||||
// FIXME: gcc 4.9 does not like MakeWaypoints to be protected
|
||||
// protected:
|
||||
util::json::Object MakeWaypoint(const PhantomNode &phantom) const
|
||||
util::json::Object MakeWaypoint(const PhantomNodeCandidates &candidates) const
|
||||
{
|
||||
// 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)
|
||||
{
|
||||
// TODO: check forward/reverse
|
||||
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(
|
||||
phantom.location,
|
||||
util::coordinate_calculation::greatCircleDistance(phantom.location,
|
||||
phantom.input_location),
|
||||
facade.GetNameForID(facade.GetNameIndex(phantom.forward_segment_id.id)).to_string(),
|
||||
Hint{phantom, facade.GetCheckSum()});
|
||||
snapped_location,
|
||||
util::coordinate_calculation::greatCircleDistance(snapped_location, input_location),
|
||||
waypoint_name,
|
||||
{std::move(seg_hints)});
|
||||
}
|
||||
else
|
||||
{
|
||||
// TODO: check forward/reverse
|
||||
return json::makeWaypoint(
|
||||
phantom.location,
|
||||
util::coordinate_calculation::greatCircleDistance(phantom.location,
|
||||
phantom.input_location),
|
||||
facade.GetNameForID(facade.GetNameIndex(phantom.forward_segment_id.id))
|
||||
.to_string());
|
||||
snapped_location,
|
||||
util::coordinate_calculation::greatCircleDistance(snapped_location, input_location),
|
||||
waypoint_name);
|
||||
}
|
||||
}
|
||||
|
||||
flatbuffers::Offset<flatbuffers::Vector<flatbuffers::Offset<fbresult::Waypoint>>>
|
||||
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() == segment_end_coordinates.size() + 1);
|
||||
BOOST_ASSERT(parameters.coordinates.size() == waypoint_candidates.size());
|
||||
|
||||
std::vector<flatbuffers::Offset<fbresult::Waypoint>> waypoints;
|
||||
waypoints.resize(parameters.coordinates.size());
|
||||
waypoints[0] =
|
||||
MakeWaypoint(builder, segment_end_coordinates.front().source_phantom)->Finish();
|
||||
|
||||
std::transform(segment_end_coordinates.begin(),
|
||||
segment_end_coordinates.end(),
|
||||
std::next(waypoints.begin()),
|
||||
[this, builder](const PhantomNodes &phantom_pair) {
|
||||
return MakeWaypoint(builder, phantom_pair.target_phantom)->Finish();
|
||||
std::transform(waypoint_candidates.begin(),
|
||||
waypoint_candidates.end(),
|
||||
waypoints.begin(),
|
||||
[this, builder](const PhantomNodeCandidates &candidates) {
|
||||
return MakeWaypoint(builder, candidates)->Finish();
|
||||
});
|
||||
return builder->CreateVector(waypoints);
|
||||
}
|
||||
|
||||
// FIXME: gcc 4.9 does not like MakeWaypoints to be protected
|
||||
// protected:
|
||||
std::unique_ptr<fbresult::WaypointBuilder> MakeWaypoint(flatbuffers::FlatBufferBuilder *builder,
|
||||
const PhantomNode &phantom) const
|
||||
std::unique_ptr<fbresult::WaypointBuilder>
|
||||
MakeWaypoint(flatbuffers::FlatBufferBuilder *builder,
|
||||
const PhantomNodeCandidates &candidates) const
|
||||
{
|
||||
|
||||
const auto &snapped_location = candidatesSnappedLocation(candidates);
|
||||
const auto &input_location = candidatesInputLocation(candidates);
|
||||
auto location =
|
||||
fbresult::Position(static_cast<double>(util::toFloating(phantom.location.lon)),
|
||||
static_cast<double>(util::toFloating(phantom.location.lat)));
|
||||
auto name_string = builder->CreateString(
|
||||
facade.GetNameForID(facade.GetNameIndex(phantom.forward_segment_id.id)).to_string());
|
||||
fbresult::Position(static_cast<double>(util::toFloating(snapped_location.lon)),
|
||||
static_cast<double>(util::toFloating(snapped_location.lat)));
|
||||
|
||||
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;
|
||||
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);
|
||||
waypoint->add_location(&location);
|
||||
waypoint->add_distance(util::coordinate_calculation::greatCircleDistance(
|
||||
phantom.location, phantom.input_location));
|
||||
waypoint->add_distance(
|
||||
util::coordinate_calculation::greatCircleDistance(snapped_location, input_location));
|
||||
waypoint->add_name(name_string);
|
||||
if (parameters.generate_hints)
|
||||
{
|
||||
|
@ -51,14 +51,14 @@ namespace api
|
||||
* Holds member attributes:
|
||||
* - coordinates: for specifying location(s) to services
|
||||
* - 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,
|
||||
* optional per coordinate
|
||||
* - 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
|
||||
* - 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
|
||||
*/
|
||||
struct BaseParameters
|
||||
|
@ -76,7 +76,7 @@ class MatchAPI final : public RouteAPI
|
||||
routes.values.reserve(number_of_routes);
|
||||
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].source_traversed_in_reverse,
|
||||
sub_routes[index].target_traversed_in_reverse);
|
||||
@ -146,7 +146,7 @@ class MatchAPI final : public RouteAPI
|
||||
}
|
||||
const auto &phantom =
|
||||
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_alternatives_count(sub_matchings[matching_index.sub_matching_index]
|
||||
.alternatives_count[matching_index.point_index]);
|
||||
@ -200,7 +200,7 @@ class MatchAPI final : public RouteAPI
|
||||
}
|
||||
const auto &phantom =
|
||||
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["waypoint_index"] = matching_index.point_index;
|
||||
waypoint.values["alternatives_count"] =
|
||||
|
@ -71,7 +71,7 @@ class NearestAPI final : public BaseAPI
|
||||
auto node_values = MakeNodes(phantom_node);
|
||||
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);
|
||||
return waypoint->Finish();
|
||||
});
|
||||
@ -100,7 +100,7 @@ class NearestAPI final : public BaseAPI
|
||||
waypoints.values.begin(),
|
||||
[this](const PhantomNodeWithDistance &phantom_with_distance) {
|
||||
auto &phantom_node = phantom_with_distance.phantom_node;
|
||||
auto waypoint = MakeWaypoint(phantom_node);
|
||||
auto waypoint = MakeWaypoint({phantom_node});
|
||||
|
||||
util::json::Array nodes;
|
||||
|
||||
|
@ -47,8 +47,8 @@ class RouteAPI : public BaseAPI
|
||||
|
||||
void
|
||||
MakeResponse(const InternalManyRoutesResult &raw_routes,
|
||||
const std::vector<PhantomNodes>
|
||||
&all_start_end_points, // all used coordinates, ignoring waypoints= parameter
|
||||
const std::vector<PhantomNodeCandidates>
|
||||
&waypoint_candidates, // all used coordinates, ignoring waypoints= parameter
|
||||
osrm::engine::api::ResultT &response) const
|
||||
{
|
||||
BOOST_ASSERT(!raw_routes.routes.empty());
|
||||
@ -56,19 +56,19 @@ class RouteAPI : public BaseAPI
|
||||
if (response.is<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
|
||||
{
|
||||
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
|
||||
MakeResponse(const InternalManyRoutesResult &raw_routes,
|
||||
const std::vector<PhantomNodes>
|
||||
&all_start_end_points, // all used coordinates, ignoring waypoints= parameter
|
||||
const std::vector<PhantomNodeCandidates>
|
||||
&waypoint_candidates, // all used coordinates, ignoring waypoints= parameter
|
||||
flatbuffers::FlatBufferBuilder &fb_result) const
|
||||
{
|
||||
|
||||
@ -80,8 +80,8 @@ class RouteAPI : public BaseAPI
|
||||
}
|
||||
|
||||
auto response =
|
||||
MakeFBResponse(raw_routes, fb_result, [this, &all_start_end_points, &fb_result]() {
|
||||
return BaseAPI::MakeWaypoints(&fb_result, all_start_end_points);
|
||||
MakeFBResponse(raw_routes, fb_result, [this, &waypoint_candidates, &fb_result]() {
|
||||
return BaseAPI::MakeWaypoints(&fb_result, waypoint_candidates);
|
||||
});
|
||||
|
||||
if (!data_timestamp.empty())
|
||||
@ -93,8 +93,8 @@ class RouteAPI : public BaseAPI
|
||||
|
||||
void
|
||||
MakeResponse(const InternalManyRoutesResult &raw_routes,
|
||||
const std::vector<PhantomNodes>
|
||||
&all_start_end_points, // all used coordinates, ignoring waypoints= parameter
|
||||
const std::vector<PhantomNodeCandidates>
|
||||
&waypoint_candidates, // all used coordinates, ignoring waypoints= parameter
|
||||
util::json::Object &response) const
|
||||
{
|
||||
util::json::Array jsRoutes;
|
||||
@ -104,7 +104,7 @@ class RouteAPI : public BaseAPI
|
||||
if (!route.is_valid())
|
||||
continue;
|
||||
|
||||
jsRoutes.values.push_back(MakeRoute(route.segment_end_coordinates,
|
||||
jsRoutes.values.push_back(MakeRoute(route.leg_endpoints,
|
||||
route.unpacked_path_segments,
|
||||
route.source_traversed_in_reverse,
|
||||
route.target_traversed_in_reverse));
|
||||
@ -112,7 +112,7 @@ class RouteAPI : public BaseAPI
|
||||
|
||||
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["code"] = "Ok";
|
||||
@ -138,7 +138,7 @@ class RouteAPI : public BaseAPI
|
||||
continue;
|
||||
|
||||
routes.push_back(MakeRoute(fb_result,
|
||||
raw_route.segment_end_coordinates,
|
||||
raw_route.leg_endpoints,
|
||||
raw_route.unpacked_path_segments,
|
||||
raw_route.source_traversed_in_reverse,
|
||||
raw_route.target_traversed_in_reverse));
|
||||
@ -328,12 +328,12 @@ class RouteAPI : public BaseAPI
|
||||
|
||||
flatbuffers::Offset<fbresult::RouteObject>
|
||||
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<bool> &source_traversed_in_reverse,
|
||||
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,
|
||||
source_traversed_in_reverse,
|
||||
target_traversed_in_reverse);
|
||||
@ -705,12 +705,12 @@ class RouteAPI : public BaseAPI
|
||||
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<bool> &source_traversed_in_reverse,
|
||||
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,
|
||||
source_traversed_in_reverse,
|
||||
target_traversed_in_reverse);
|
||||
@ -868,7 +868,7 @@ class RouteAPI : public BaseAPI
|
||||
const RouteParameters ¶meters;
|
||||
|
||||
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<bool> &source_traversed_in_reverse,
|
||||
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>());
|
||||
auto &legs = result.first;
|
||||
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);
|
||||
leg_geometries.reserve(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 bool reversed_source = source_traversed_in_reverse[idx];
|
||||
|
@ -48,25 +48,25 @@ class TableAPI final : public BaseAPI
|
||||
|
||||
virtual void
|
||||
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,
|
||||
osrm::engine::api::ResultT &response) const
|
||||
{
|
||||
if (response.is<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
|
||||
{
|
||||
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
|
||||
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,
|
||||
flatbuffers::FlatBufferBuilder &fb_result) const
|
||||
{
|
||||
@ -86,15 +86,15 @@ class TableAPI final : public BaseAPI
|
||||
{
|
||||
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
|
||||
{
|
||||
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)
|
||||
{
|
||||
destinations = MakeWaypoints(fb_result, phantoms);
|
||||
destinations = MakeWaypoints(fb_result, candidates);
|
||||
}
|
||||
number_of_destinations = phantoms.size();
|
||||
number_of_destinations = candidates.size();
|
||||
}
|
||||
else
|
||||
{
|
||||
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
|
||||
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,
|
||||
util::json::Object &response) const
|
||||
{
|
||||
@ -180,15 +180,15 @@ class TableAPI final : public BaseAPI
|
||||
{
|
||||
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
|
||||
{
|
||||
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)
|
||||
{
|
||||
response.values["destinations"] = MakeWaypoints(phantoms);
|
||||
response.values["destinations"] = MakeWaypoints(candidates);
|
||||
}
|
||||
number_of_destinations = phantoms.size();
|
||||
number_of_destinations = candidates.size();
|
||||
}
|
||||
else
|
||||
{
|
||||
if (!parameters.skip_waypoints)
|
||||
{
|
||||
response.values["destinations"] = MakeWaypoints(phantoms, parameters.destinations);
|
||||
response.values["destinations"] =
|
||||
MakeWaypoints(candidates, parameters.destinations);
|
||||
}
|
||||
}
|
||||
|
||||
@ -236,32 +237,34 @@ class TableAPI final : public BaseAPI
|
||||
protected:
|
||||
virtual flatbuffers::Offset<flatbuffers::Vector<flatbuffers::Offset<fbresult::Waypoint>>>
|
||||
MakeWaypoints(flatbuffers::FlatBufferBuilder &builder,
|
||||
const std::vector<PhantomNode> &phantoms) const
|
||||
const std::vector<PhantomNodeCandidates> &candidates) const
|
||||
{
|
||||
std::vector<flatbuffers::Offset<fbresult::Waypoint>> waypoints;
|
||||
waypoints.reserve(phantoms.size());
|
||||
BOOST_ASSERT(phantoms.size() == parameters.coordinates.size());
|
||||
waypoints.reserve(candidates.size());
|
||||
BOOST_ASSERT(candidates.size() == parameters.coordinates.size());
|
||||
|
||||
boost::range::transform(
|
||||
phantoms, std::back_inserter(waypoints), [this, &builder](const PhantomNode &phantom) {
|
||||
return BaseAPI::MakeWaypoint(&builder, phantom)->Finish();
|
||||
});
|
||||
boost::range::transform(candidates,
|
||||
std::back_inserter(waypoints),
|
||||
[this, &builder](const PhantomNodeCandidates &candidates) {
|
||||
return BaseAPI::MakeWaypoint(&builder, candidates)->Finish();
|
||||
});
|
||||
return builder.CreateVector(waypoints);
|
||||
}
|
||||
|
||||
virtual flatbuffers::Offset<flatbuffers::Vector<flatbuffers::Offset<fbresult::Waypoint>>>
|
||||
MakeWaypoints(flatbuffers::FlatBufferBuilder &builder,
|
||||
const std::vector<PhantomNode> &phantoms,
|
||||
const std::vector<PhantomNodeCandidates> &candidates,
|
||||
const std::vector<std::size_t> &indices) const
|
||||
{
|
||||
std::vector<flatbuffers::Offset<fbresult::Waypoint>> waypoints;
|
||||
waypoints.reserve(indices.size());
|
||||
boost::range::transform(indices,
|
||||
std::back_inserter(waypoints),
|
||||
[this, &builder, phantoms](const std::size_t idx) {
|
||||
BOOST_ASSERT(idx < phantoms.size());
|
||||
return BaseAPI::MakeWaypoint(&builder, phantoms[idx])->Finish();
|
||||
});
|
||||
boost::range::transform(
|
||||
indices,
|
||||
std::back_inserter(waypoints),
|
||||
[this, &builder, &candidates](const std::size_t idx) {
|
||||
BOOST_ASSERT(idx < candidates.size());
|
||||
return BaseAPI::MakeWaypoint(&builder, candidates[idx])->Finish();
|
||||
});
|
||||
return builder.CreateVector(waypoints);
|
||||
}
|
||||
|
||||
@ -313,29 +316,31 @@ class TableAPI final : public BaseAPI
|
||||
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;
|
||||
json_waypoints.values.reserve(phantoms.size());
|
||||
BOOST_ASSERT(phantoms.size() == parameters.coordinates.size());
|
||||
json_waypoints.values.reserve(candidates.size());
|
||||
BOOST_ASSERT(candidates.size() == parameters.coordinates.size());
|
||||
|
||||
boost::range::transform(
|
||||
phantoms,
|
||||
std::back_inserter(json_waypoints.values),
|
||||
[this](const PhantomNode &phantom) { return BaseAPI::MakeWaypoint(phantom); });
|
||||
boost::range::transform(candidates,
|
||||
std::back_inserter(json_waypoints.values),
|
||||
[this](const PhantomNodeCandidates &candidates) {
|
||||
return BaseAPI::MakeWaypoint(candidates);
|
||||
});
|
||||
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
|
||||
{
|
||||
util::json::Array json_waypoints;
|
||||
json_waypoints.values.reserve(indices.size());
|
||||
boost::range::transform(indices,
|
||||
std::back_inserter(json_waypoints.values),
|
||||
[this, phantoms](const std::size_t idx) {
|
||||
BOOST_ASSERT(idx < phantoms.size());
|
||||
return BaseAPI::MakeWaypoint(phantoms[idx]);
|
||||
[this, &candidates](const std::size_t idx) {
|
||||
BOOST_ASSERT(idx < candidates.size());
|
||||
return BaseAPI::MakeWaypoint(candidates[idx]);
|
||||
});
|
||||
return json_waypoints;
|
||||
}
|
||||
|
@ -26,7 +26,7 @@ class TripAPI final : public RouteAPI
|
||||
}
|
||||
void MakeResponse(const std::vector<std::vector<NodeID>> &sub_trips,
|
||||
const std::vector<InternalRouteResult> &sub_routes,
|
||||
const std::vector<PhantomNode> &phantoms,
|
||||
const std::vector<PhantomNodeCandidates> &candidates,
|
||||
osrm::engine::api::ResultT &response) const
|
||||
{
|
||||
BOOST_ASSERT(sub_trips.size() == sub_routes.size());
|
||||
@ -34,17 +34,17 @@ class TripAPI final : public RouteAPI
|
||||
if (response.is<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
|
||||
{
|
||||
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,
|
||||
const std::vector<InternalRouteResult> &sub_routes,
|
||||
const std::vector<PhantomNode> &phantoms,
|
||||
const std::vector<PhantomNodeCandidates> &candidates,
|
||||
flatbuffers::FlatBufferBuilder &fb_result) const
|
||||
{
|
||||
auto data_timestamp = facade.GetTimestamp();
|
||||
@ -55,8 +55,8 @@ class TripAPI final : public RouteAPI
|
||||
}
|
||||
|
||||
auto response =
|
||||
MakeFBResponse(sub_routes, fb_result, [this, &fb_result, &sub_trips, &phantoms]() {
|
||||
return MakeWaypoints(fb_result, sub_trips, phantoms);
|
||||
MakeFBResponse(sub_routes, fb_result, [this, &fb_result, &sub_trips, &candidates]() {
|
||||
return MakeWaypoints(fb_result, sub_trips, candidates);
|
||||
});
|
||||
|
||||
if (!data_timestamp.empty())
|
||||
@ -67,7 +67,7 @@ class TripAPI final : public RouteAPI
|
||||
}
|
||||
void MakeResponse(const std::vector<std::vector<NodeID>> &sub_trips,
|
||||
const std::vector<InternalRouteResult> &sub_routes,
|
||||
const std::vector<PhantomNode> &phantoms,
|
||||
const std::vector<PhantomNodeCandidates> &candidates,
|
||||
util::json::Object &response) const
|
||||
{
|
||||
auto number_of_routes = sub_trips.size();
|
||||
@ -75,7 +75,7 @@ class TripAPI final : public RouteAPI
|
||||
routes.values.reserve(number_of_routes);
|
||||
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].source_traversed_in_reverse,
|
||||
sub_routes[index].target_traversed_in_reverse);
|
||||
@ -83,7 +83,7 @@ class TripAPI final : public RouteAPI
|
||||
}
|
||||
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["code"] = "Ok";
|
||||
@ -120,7 +120,7 @@ class TripAPI final : public RouteAPI
|
||||
flatbuffers::Offset<flatbuffers::Vector<flatbuffers::Offset<fbresult::Waypoint>>>
|
||||
MakeWaypoints(flatbuffers::FlatBufferBuilder &fb_result,
|
||||
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;
|
||||
waypoints.reserve(parameters.coordinates.size());
|
||||
@ -132,7 +132,7 @@ class TripAPI final : public RouteAPI
|
||||
auto trip_index = input_idx_to_trip_idx[input_index];
|
||||
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_trips_index(trip_index.sub_trip_index);
|
||||
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,
|
||||
const std::vector<PhantomNode> &phantoms) const
|
||||
const std::vector<PhantomNodeCandidates> &candidates) const
|
||||
{
|
||||
util::json::Array waypoints;
|
||||
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];
|
||||
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["waypoint_index"] = trip_index.point_index;
|
||||
waypoints.values.push_back(std::move(waypoint));
|
||||
|
@ -323,127 +323,41 @@ class ContiguousInternalMemoryDataFacadeBase : public BaseDataFacade
|
||||
|
||||
std::vector<PhantomNodeWithDistance>
|
||||
NearestPhantomNodesInRange(const util::Coordinate input_coordinate,
|
||||
const float 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->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);
|
||||
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 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 size_t max_results,
|
||||
const boost::optional<double> max_distance,
|
||||
const boost::optional<Bearing> bearing,
|
||||
const Approach approach) const override final
|
||||
{
|
||||
BOOST_ASSERT(m_geospatial_query.get());
|
||||
|
||||
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>
|
||||
NearestPhantomNodes(const util::Coordinate input_coordinate,
|
||||
const unsigned max_results,
|
||||
const int bearing,
|
||||
const int bearing_range,
|
||||
const Approach approach) const override final
|
||||
PhantomCandidateAlternatives
|
||||
NearestCandidatesWithAlternativeFromBigComponent(const util::Coordinate input_coordinate,
|
||||
const boost::optional<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, 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 bool use_all_edges) const override final
|
||||
{
|
||||
BOOST_ASSERT(m_geospatial_query.get());
|
||||
|
||||
return m_geospatial_query->NearestPhantomNodeWithAlternativeFromBigComponent(
|
||||
input_coordinate, approach, 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);
|
||||
return m_geospatial_query->NearestCandidatesWithAlternativeFromBigComponent(
|
||||
input_coordinate, approach, max_distance, bearing, use_all_edges);
|
||||
}
|
||||
|
||||
std::uint32_t GetCheckSum() const override final { return m_check_sum; }
|
||||
|
@ -35,6 +35,7 @@
|
||||
#include <boost/range/any_range.hpp>
|
||||
#include <cstddef>
|
||||
|
||||
#include <engine/bearing.hpp>
|
||||
#include <string>
|
||||
#include <utility>
|
||||
#include <vector>
|
||||
@ -130,62 +131,24 @@ class BaseDataFacade
|
||||
|
||||
virtual 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 = 0;
|
||||
virtual std::vector<PhantomNodeWithDistance>
|
||||
NearestPhantomNodesInRange(const util::Coordinate input_coordinate,
|
||||
const float max_distance,
|
||||
const double max_distance,
|
||||
const boost::optional<Bearing> bearing,
|
||||
const Approach approach,
|
||||
const bool use_all_edges) const = 0;
|
||||
|
||||
virtual 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 = 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 size_t max_results,
|
||||
const boost::optional<double> max_distance,
|
||||
const boost::optional<Bearing> bearing,
|
||||
const Approach approach) const = 0;
|
||||
|
||||
virtual std::pair<PhantomNode, PhantomNode>
|
||||
NearestPhantomNodeWithAlternativeFromBigComponent(const util::Coordinate input_coordinate,
|
||||
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 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 PhantomCandidateAlternatives
|
||||
NearestCandidatesWithAlternativeFromBigComponent(const util::Coordinate input_coordinate,
|
||||
const boost::optional<double> max_distance,
|
||||
const boost::optional<Bearing> bearing,
|
||||
const Approach approach,
|
||||
const bool use_all_edges) 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;
|
||||
|
@ -2,6 +2,7 @@
|
||||
#define GEOSPATIAL_QUERY_HPP
|
||||
|
||||
#include "engine/approach.hpp"
|
||||
#include "engine/bearing.hpp"
|
||||
#include "engine/phantom_node.hpp"
|
||||
#include "util/bearing.hpp"
|
||||
#include "util/coordinate_calculation.hpp"
|
||||
@ -22,10 +23,10 @@ namespace osrm
|
||||
namespace engine
|
||||
{
|
||||
|
||||
inline std::pair<bool, bool> boolPairAnd(const std::pair<bool, bool> &A,
|
||||
const std::pair<bool, bool> &B)
|
||||
inline std::pair<bool, bool> operator&&(const std::pair<bool, bool> &a,
|
||||
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.
|
||||
@ -48,390 +49,241 @@ template <typename RTreeT, typename DataFacadeT> class GeospatialQuery
|
||||
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!
|
||||
std::vector<PhantomNodeWithDistance>
|
||||
NearestPhantomNodesInRange(const util::Coordinate input_coordinate,
|
||||
const double max_distance,
|
||||
const Approach approach,
|
||||
const bool use_all_edges) const
|
||||
NearestPhantomNodes(const util::Coordinate input_coordinate,
|
||||
const Approach approach,
|
||||
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(
|
||||
input_coordinate,
|
||||
[this, approach, &input_coordinate, use_all_edges](const CandidateSegment &segment) {
|
||||
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) {
|
||||
return CheckSegmentDistance(input_coordinate, segment, max_distance);
|
||||
});
|
||||
|
||||
return MakePhantomNodes(input_coordinate, results);
|
||||
}
|
||||
|
||||
// Returns nearest PhantomNodes in the given bearing range within max_distance.
|
||||
// Does not filter by small/big component!
|
||||
std::vector<PhantomNodeWithDistance>
|
||||
NearestPhantomNodesInRange(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
|
||||
{
|
||||
auto results = rtree.Nearest(
|
||||
input_coordinate,
|
||||
[this, approach, &input_coordinate, bearing, bearing_range, use_all_edges](
|
||||
[this, approach, &input_coordinate, &bearing_with_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;
|
||||
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, input_coordinate](const std::size_t,
|
||||
const CandidateSegment &segment) {
|
||||
return CheckSegmentDistance(input_coordinate, segment, max_distance);
|
||||
[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);
|
||||
}
|
||||
|
||||
// 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
|
||||
// Returns a list of phantom node candidates from the nearest location that are valid
|
||||
// within the provided parameters. If there is tie between equidistant locations,
|
||||
// we only pick candidates from one location.
|
||||
// If candidates do not include a node from a big component, an alternative list of candidates
|
||||
// from the nearest location which has nodes from a big component is returned.
|
||||
PhantomCandidateAlternatives NearestCandidatesWithAlternativeFromBigComponent(
|
||||
const util::Coordinate input_coordinate,
|
||||
const Approach approach,
|
||||
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(
|
||||
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_nearest = 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(
|
||||
input_coordinate,
|
||||
[this,
|
||||
approach,
|
||||
&input_coordinate,
|
||||
&has_nearest,
|
||||
&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));
|
||||
&nearest_coord,
|
||||
&big_component_coord,
|
||||
&big_component_distance,
|
||||
&use_all_edges,
|
||||
&bearing_with_range](const CandidateSegment &segment) {
|
||||
auto is_big_component = !IsTinyComponent(segment);
|
||||
auto not_nearest =
|
||||
has_nearest && segment.fixed_projected_coordinate != nearest_coord;
|
||||
auto not_big =
|
||||
has_big_component && segment.fixed_projected_coordinate != big_component_coord;
|
||||
|
||||
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);
|
||||
has_small_component = has_small_component || IsTinyComponent(segment);
|
||||
return std::make_pair(false, false);
|
||||
}
|
||||
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));
|
||||
|
||||
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() == 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)
|
||||
if (use_candidate.first || use_candidate.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)
|
||||
if (!has_nearest)
|
||||
{
|
||||
has_big_component = has_big_component || !IsTinyComponent(segment);
|
||||
has_small_component = has_small_component || IsTinyComponent(segment);
|
||||
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;
|
||||
},
|
||||
[&has_big_component](const std::size_t num_results, const CandidateSegment &) {
|
||||
return num_results > 0 && has_big_component;
|
||||
[this, &has_big_component, &max_distance, input_coordinate, &big_component_distance](
|
||||
const std::size_t /*num_results*/, const CandidateSegment &segment) {
|
||||
auto distance = GetSegmentDistance(input_coordinate, segment);
|
||||
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 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);
|
||||
return MakeAlternativeBigCandidates(input_coordinate, nearest_coord, results);
|
||||
}
|
||||
|
||||
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>
|
||||
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::transform(results.begin(),
|
||||
results.end(),
|
||||
distance_and_phantoms.begin(),
|
||||
[this, &input_coordinate](const EdgeData &data) {
|
||||
return MakePhantomNode(input_coordinate, data);
|
||||
[this, &input_coordinate](const CandidateSegment &segment) {
|
||||
return MakePhantomNode(input_coordinate, segment.data);
|
||||
});
|
||||
return distance_and_phantoms;
|
||||
}
|
||||
@ -580,9 +432,8 @@ template <typename RTreeT, typename DataFacadeT> class GeospatialQuery
|
||||
return transformed;
|
||||
}
|
||||
|
||||
bool CheckSegmentDistance(const Coordinate input_coordinate,
|
||||
const CandidateSegment &segment,
|
||||
const double max_distance) const
|
||||
double GetSegmentDistance(const Coordinate input_coordinate,
|
||||
const CandidateSegment &segment) const
|
||||
{
|
||||
BOOST_ASSERT(segment.data.forward_segment_id.id != SPECIAL_SEGMENTID ||
|
||||
!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);
|
||||
|
||||
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
|
||||
@ -616,8 +474,7 @@ template <typename RTreeT, typename DataFacadeT> class GeospatialQuery
|
||||
}
|
||||
|
||||
std::pair<bool, bool> CheckSegmentBearing(const CandidateSegment &segment,
|
||||
const int filter_bearing,
|
||||
const int filter_bearing_range) const
|
||||
const Bearing filter_bearing) const
|
||||
{
|
||||
BOOST_ASSERT(segment.data.forward_segment_id.id != SPECIAL_SEGMENTID ||
|
||||
!segment.data.forward_segment_id.enabled);
|
||||
@ -633,11 +490,11 @@ template <typename RTreeT, typename DataFacadeT> class GeospatialQuery
|
||||
|
||||
const bool forward_bearing_valid =
|
||||
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;
|
||||
const bool backward_bearing_valid =
|
||||
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;
|
||||
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,
|
||||
* 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.
|
||||
*/
|
||||
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
|
||||
{
|
||||
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);
|
||||
return datafacade.GetComponentID(data.forward_segment_id.id).is_tiny;
|
||||
}
|
||||
|
@ -47,8 +47,9 @@ namespace datafacade
|
||||
class BaseDataFacade;
|
||||
}
|
||||
|
||||
// Is returned as a temporary identifier for snapped coodinates
|
||||
struct Hint
|
||||
// SegmentHint represents an individual segment position that could be used
|
||||
// as the waypoint for a given input location
|
||||
struct SegmentHint
|
||||
{
|
||||
PhantomNode phantom;
|
||||
std::uint32_t data_checksum;
|
||||
@ -57,16 +58,31 @@ struct Hint
|
||||
const datafacade::BaseDataFacade &facade) 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 std::ostream &operator<<(std::ostream &, const Hint &);
|
||||
friend bool operator==(const SegmentHint &, const SegmentHint &);
|
||||
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");
|
||||
constexpr std::size_t ENCODED_HINT_SIZE = 112;
|
||||
static_assert(ENCODED_HINT_SIZE / 4 * 3 >= sizeof(Hint),
|
||||
"ENCODED_HINT_SIZE does not match size of Hint");
|
||||
// Hint represents the suggested segment positions that could be used
|
||||
// as the waypoint for a given input location
|
||||
struct 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 osrm
|
||||
|
||||
|
@ -50,7 +50,7 @@ struct PathData
|
||||
struct InternalRouteResult
|
||||
{
|
||||
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> target_traversed_in_reverse;
|
||||
EdgeWeight shortest_path_weight = INVALID_EDGE_WEIGHT;
|
||||
@ -96,7 +96,7 @@ inline InternalRouteResult CollapseInternalRouteResult(const InternalRouteResult
|
||||
if (leggy_result.unpacked_path_segments.size() == 1)
|
||||
return leggy_result;
|
||||
|
||||
BOOST_ASSERT(leggy_result.segment_end_coordinates.size() > 1);
|
||||
BOOST_ASSERT(leggy_result.leg_endpoints.size() > 1);
|
||||
|
||||
InternalRouteResult collapsed;
|
||||
collapsed.shortest_path_weight = leggy_result.shortest_path_weight;
|
||||
@ -107,7 +107,7 @@ inline InternalRouteResult CollapseInternalRouteResult(const InternalRouteResult
|
||||
// start another leg vector
|
||||
collapsed.unpacked_path_segments.push_back(leggy_result.unpacked_path_segments[i]);
|
||||
// save new phantom node pair
|
||||
collapsed.segment_end_coordinates.push_back(leggy_result.segment_end_coordinates[i]);
|
||||
collapsed.leg_endpoints.push_back(leggy_result.leg_endpoints[i]);
|
||||
// save data about phantom nodes
|
||||
collapsed.source_traversed_in_reverse.push_back(
|
||||
leggy_result.source_traversed_in_reverse[i]);
|
||||
@ -119,9 +119,9 @@ inline InternalRouteResult CollapseInternalRouteResult(const InternalRouteResult
|
||||
{
|
||||
BOOST_ASSERT(!collapsed.unpacked_path_segments.empty());
|
||||
auto &last_segment = collapsed.unpacked_path_segments.back();
|
||||
BOOST_ASSERT(!collapsed.segment_end_coordinates.empty());
|
||||
collapsed.segment_end_coordinates.back().target_phantom =
|
||||
leggy_result.segment_end_coordinates[i].target_phantom;
|
||||
BOOST_ASSERT(!collapsed.leg_endpoints.empty());
|
||||
collapsed.leg_endpoints.back().target_phantom =
|
||||
leggy_result.leg_endpoints[i].target_phantom;
|
||||
collapsed.target_traversed_in_reverse.back() =
|
||||
leggy_result.target_traversed_in_reverse[i];
|
||||
// copy path segments into current leg
|
||||
@ -138,19 +138,18 @@ inline InternalRouteResult CollapseInternalRouteResult(const InternalRouteResult
|
||||
last_segment[old_size].weight_until_turn +=
|
||||
|
||||
leggy_result.source_traversed_in_reverse[i]
|
||||
? leggy_result.segment_end_coordinates[i].source_phantom.reverse_weight
|
||||
: leggy_result.segment_end_coordinates[i].source_phantom.forward_weight;
|
||||
? leggy_result.leg_endpoints[i].source_phantom.reverse_weight
|
||||
: leggy_result.leg_endpoints[i].source_phantom.forward_weight;
|
||||
|
||||
last_segment[old_size].duration_until_turn +=
|
||||
leggy_result.source_traversed_in_reverse[i]
|
||||
? leggy_result.segment_end_coordinates[i].source_phantom.reverse_duration
|
||||
: leggy_result.segment_end_coordinates[i].source_phantom.forward_duration;
|
||||
? leggy_result.leg_endpoints[i].source_phantom.reverse_duration
|
||||
: leggy_result.leg_endpoints[i].source_phantom.forward_duration;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
BOOST_ASSERT(collapsed.segment_end_coordinates.size() ==
|
||||
collapsed.unpacked_path_segments.size());
|
||||
BOOST_ASSERT(collapsed.leg_endpoints.size() == collapsed.unpacked_path_segments.size());
|
||||
return collapsed;
|
||||
}
|
||||
} // namespace engine
|
||||
|
@ -28,6 +28,8 @@ SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
#ifndef OSRM_ENGINE_PHANTOM_NODES_H
|
||||
#define OSRM_ENGINE_PHANTOM_NODES_H
|
||||
|
||||
#include <vector>
|
||||
|
||||
#include "extractor/travel_mode.hpp"
|
||||
|
||||
#include "util/bearing.hpp"
|
||||
@ -223,7 +225,8 @@ struct PhantomNode
|
||||
|
||||
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
|
||||
{
|
||||
@ -231,11 +234,44 @@ struct PhantomNodeWithDistance
|
||||
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 target_phantom;
|
||||
};
|
||||
|
||||
} // namespace engine
|
||||
} // namespace osrm
|
||||
|
||||
|
@ -99,64 +99,67 @@ class BasePlugin
|
||||
return Status::Error;
|
||||
}
|
||||
|
||||
// Decides whether to use the phantom node from a big or small component if both are found.
|
||||
// Returns true if all phantom nodes are in the same component after snapping.
|
||||
std::vector<PhantomNode>
|
||||
SnapPhantomNodes(const std::vector<PhantomNodePair> &phantom_node_pair_list) const
|
||||
// Decides whether to use the phantom candidates from big or small components if both are found.
|
||||
std::vector<PhantomNodeCandidates>
|
||||
SnapPhantomNodes(std::vector<PhantomCandidateAlternatives> alternatives_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?
|
||||
const auto check_all_in_same_component =
|
||||
[](const std::vector<std::pair<PhantomNode, PhantomNode>> &nodes) {
|
||||
const auto component_id = nodes.front().first.component.id;
|
||||
|
||||
return std::all_of(std::begin(nodes),
|
||||
std::end(nodes),
|
||||
[component_id](const PhantomNodePair &phantom_pair) {
|
||||
return component_id == phantom_pair.first.component.id;
|
||||
});
|
||||
const auto all_in_same_tiny_component =
|
||||
[](const std::vector<PhantomCandidateAlternatives> &alts_list) {
|
||||
return std::any_of(
|
||||
alts_list.front().first.begin(),
|
||||
alts_list.front().first.end(),
|
||||
// For each of the first possible phantoms, check if all other
|
||||
// positions in the list have a phantom from the same small component.
|
||||
[&](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 =
|
||||
[](const std::pair<PhantomNode, PhantomNode> &phantom_pair) {
|
||||
if (phantom_pair.first.component.is_tiny && phantom_pair.second.IsValid() &&
|
||||
!phantom_pair.second.component.is_tiny)
|
||||
{
|
||||
return phantom_pair.second;
|
||||
}
|
||||
return phantom_pair.first;
|
||||
};
|
||||
// Move the alternative into the final list
|
||||
const auto fallback_to_big_component = [](PhantomCandidateAlternatives &alternatives) {
|
||||
auto no_big_alternative = alternatives.second.empty();
|
||||
return no_big_alternative ? std::move(alternatives.first)
|
||||
: std::move(alternatives.second);
|
||||
};
|
||||
|
||||
const auto use_closed_phantom =
|
||||
[](const std::pair<PhantomNode, PhantomNode> &phantom_pair) {
|
||||
return phantom_pair.first;
|
||||
};
|
||||
// Move the alternative into the final list
|
||||
const auto use_closed_phantom = [](PhantomCandidateAlternatives &alternatives) {
|
||||
return std::move(alternatives.first);
|
||||
};
|
||||
|
||||
const bool every_phantom_is_in_tiny_cc = std::all_of(std::begin(phantom_node_pair_list),
|
||||
std::end(phantom_node_pair_list),
|
||||
check_component_id_is_tiny);
|
||||
auto all_in_same_component = check_all_in_same_component(phantom_node_pair_list);
|
||||
|
||||
std::vector<PhantomNode> snapped_phantoms;
|
||||
snapped_phantoms.reserve(phantom_node_pair_list.size());
|
||||
const auto no_alternatives =
|
||||
std::all_of(alternatives_list.begin(),
|
||||
alternatives_list.end(),
|
||||
[](const PhantomCandidateAlternatives &alternatives) {
|
||||
return alternatives.second.empty();
|
||||
});
|
||||
|
||||
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
|
||||
// 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(),
|
||||
phantom_node_pair_list.end(),
|
||||
std::transform(alternatives_list.begin(),
|
||||
alternatives_list.end(),
|
||||
std::back_inserter(snapped_phantoms),
|
||||
use_closed_phantom);
|
||||
}
|
||||
else
|
||||
{
|
||||
std::transform(phantom_node_pair_list.begin(),
|
||||
phantom_node_pair_list.end(),
|
||||
std::transform(alternatives_list.begin(),
|
||||
alternatives_list.end(),
|
||||
std::back_inserter(snapped_phantoms),
|
||||
fallback_to_big_component);
|
||||
}
|
||||
@ -181,35 +184,26 @@ class BasePlugin
|
||||
|
||||
for (const auto i : util::irange<std::size_t>(0UL, parameters.coordinates.size()))
|
||||
{
|
||||
Approach approach = engine::Approach::UNRESTRICTED;
|
||||
if (use_approaches && parameters.approaches[i])
|
||||
approach = parameters.approaches[i].get();
|
||||
|
||||
if (use_hints && parameters.hints[i] &&
|
||||
if (use_hints && parameters.hints[i] && !parameters.hints[i]->segment_hints.empty() &&
|
||||
parameters.hints[i]->IsValid(parameters.coordinates[i], facade))
|
||||
{
|
||||
phantom_nodes[i].push_back(PhantomNodeWithDistance{
|
||||
parameters.hints[i]->phantom,
|
||||
util::coordinate_calculation::greatCircleDistance(
|
||||
parameters.coordinates[i], parameters.hints[i]->phantom.location),
|
||||
});
|
||||
for (const auto &seg_hint : parameters.hints[i]->segment_hints)
|
||||
{
|
||||
phantom_nodes[i].push_back(PhantomNodeWithDistance{
|
||||
seg_hint.phantom,
|
||||
util::coordinate_calculation::greatCircleDistance(
|
||||
parameters.coordinates[i], seg_hint.phantom.location)});
|
||||
}
|
||||
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(
|
||||
parameters.coordinates[i], radiuses[i], approach, use_all_edges);
|
||||
}
|
||||
|
||||
phantom_nodes[i] = facade.NearestPhantomNodesInRange(
|
||||
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;
|
||||
@ -218,7 +212,7 @@ class BasePlugin
|
||||
std::vector<std::vector<PhantomNodeWithDistance>>
|
||||
GetPhantomNodes(const datafacade::BaseDataFacade &facade,
|
||||
const api::BaseParameters ¶meters,
|
||||
unsigned number_of_results) const
|
||||
size_t number_of_results) const
|
||||
{
|
||||
std::vector<std::vector<PhantomNodeWithDistance>> phantom_nodes(
|
||||
parameters.coordinates.size());
|
||||
@ -231,56 +225,26 @@ class BasePlugin
|
||||
BOOST_ASSERT(parameters.IsValid());
|
||||
for (const auto i : util::irange<std::size_t>(0UL, parameters.coordinates.size()))
|
||||
{
|
||||
Approach approach = engine::Approach::UNRESTRICTED;
|
||||
if (use_approaches && parameters.approaches[i])
|
||||
approach = parameters.approaches[i].get();
|
||||
|
||||
if (use_hints && parameters.hints[i] &&
|
||||
if (use_hints && parameters.hints[i] && !parameters.hints[i]->segment_hints.empty() &&
|
||||
parameters.hints[i]->IsValid(parameters.coordinates[i], facade))
|
||||
{
|
||||
phantom_nodes[i].push_back(PhantomNodeWithDistance{
|
||||
parameters.hints[i]->phantom,
|
||||
util::coordinate_calculation::greatCircleDistance(
|
||||
parameters.coordinates[i], parameters.hints[i]->phantom.location),
|
||||
});
|
||||
for (const auto &seg_hint : parameters.hints[i]->segment_hints)
|
||||
{
|
||||
phantom_nodes[i].push_back(PhantomNodeWithDistance{
|
||||
seg_hint.phantom,
|
||||
util::coordinate_calculation::greatCircleDistance(
|
||||
parameters.coordinates[i], seg_hint.phantom.location)});
|
||||
}
|
||||
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(
|
||||
parameters.coordinates[i], number_of_results, approach);
|
||||
}
|
||||
}
|
||||
phantom_nodes[i] = facade.NearestPhantomNodes(
|
||||
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
|
||||
if (phantom_nodes[i].empty())
|
||||
@ -291,10 +255,11 @@ class BasePlugin
|
||||
return phantom_nodes;
|
||||
}
|
||||
|
||||
std::vector<PhantomNodePair> GetPhantomNodes(const datafacade::BaseDataFacade &facade,
|
||||
const api::BaseParameters ¶meters) const
|
||||
std::vector<PhantomCandidateAlternatives>
|
||||
GetPhantomNodes(const datafacade::BaseDataFacade &facade,
|
||||
const api::BaseParameters ¶meters) 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_bearings = !parameters.bearings.empty();
|
||||
@ -305,87 +270,57 @@ class BasePlugin
|
||||
BOOST_ASSERT(parameters.IsValid());
|
||||
for (const auto i : util::irange<std::size_t>(0UL, parameters.coordinates.size()))
|
||||
{
|
||||
Approach approach = engine::Approach::UNRESTRICTED;
|
||||
if (use_approaches && parameters.approaches[i])
|
||||
approach = parameters.approaches[i].get();
|
||||
|
||||
if (use_hints && parameters.hints[i] &&
|
||||
if (use_hints && parameters.hints[i] && !parameters.hints[i]->segment_hints.empty() &&
|
||||
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
|
||||
continue;
|
||||
}
|
||||
|
||||
if (use_bearings && parameters.bearings[i])
|
||||
{
|
||||
if (use_radiuses && parameters.radiuses[i])
|
||||
{
|
||||
phantom_node_pairs[i] =
|
||||
facade.NearestPhantomNodeWithAlternativeFromBigComponent(
|
||||
parameters.coordinates[i],
|
||||
*parameters.radiuses[i],
|
||||
parameters.bearings[i]->bearing,
|
||||
parameters.bearings[i]->range,
|
||||
approach,
|
||||
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);
|
||||
}
|
||||
}
|
||||
alternatives[i] = facade.NearestCandidatesWithAlternativeFromBigComponent(
|
||||
parameters.coordinates[i],
|
||||
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,
|
||||
use_all_edges);
|
||||
|
||||
// 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.
|
||||
// We can use this on the call-site to detect an error.
|
||||
phantom_node_pairs.pop_back();
|
||||
alternatives.pop_back();
|
||||
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,
|
||||
const std::vector<util::Coordinate> &coordinates) const
|
||||
std::string
|
||||
MissingPhantomErrorMessage(const std::vector<PhantomCandidateAlternatives> &alternatives,
|
||||
const std::vector<util::Coordinate> &coordinates) const
|
||||
{
|
||||
BOOST_ASSERT(phantom_nodes.size() < coordinates.size());
|
||||
auto mismatch = std::mismatch(phantom_nodes.begin(),
|
||||
phantom_nodes.end(),
|
||||
coordinates.begin(),
|
||||
coordinates.end(),
|
||||
[](const auto &phantom_node, const auto &coordinate) {
|
||||
return phantom_node.first.input_location == coordinate;
|
||||
});
|
||||
std::size_t missing_index = std::distance(phantom_nodes.begin(), mismatch.first);
|
||||
BOOST_ASSERT(alternatives.size() < coordinates.size());
|
||||
auto mismatch =
|
||||
std::mismatch(alternatives.begin(),
|
||||
alternatives.end(),
|
||||
coordinates.begin(),
|
||||
coordinates.end(),
|
||||
[](const auto &candidates_pair, const auto &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(alternatives.begin(), mismatch.first);
|
||||
return std::string("Could not find a matching segment for coordinate ") +
|
||||
std::to_string(missing_index);
|
||||
}
|
||||
|
@ -31,7 +31,7 @@ class TripPlugin final : public BasePlugin
|
||||
const int max_locations_trip;
|
||||
|
||||
InternalRouteResult ComputeRoute(const RoutingAlgorithmsInterface &algorithms,
|
||||
const std::vector<PhantomNode> &phantom_node_list,
|
||||
const std::vector<PhantomNodeCandidates> &candidates_list,
|
||||
const std::vector<NodeID> &trip,
|
||||
const bool roundtrip) const;
|
||||
|
||||
|
@ -20,18 +20,18 @@ class RoutingAlgorithmsInterface
|
||||
{
|
||||
public:
|
||||
virtual InternalManyRoutesResult
|
||||
AlternativePathSearch(const PhantomNodes &phantom_node_pair,
|
||||
AlternativePathSearch(const PhantomEndpointCandidates &endpoint_candidates,
|
||||
unsigned number_of_alternatives) const = 0;
|
||||
|
||||
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;
|
||||
|
||||
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>>
|
||||
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> &target_indices,
|
||||
const bool calculate_distance) const = 0;
|
||||
@ -73,18 +73,18 @@ template <typename Algorithm> class RoutingAlgorithms final : public RoutingAlgo
|
||||
virtual ~RoutingAlgorithms() = default;
|
||||
|
||||
InternalManyRoutesResult
|
||||
AlternativePathSearch(const PhantomNodes &phantom_node_pair,
|
||||
AlternativePathSearch(const PhantomEndpointCandidates &endpoint_candidates,
|
||||
unsigned number_of_alternatives) const final override;
|
||||
|
||||
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;
|
||||
|
||||
InternalRouteResult
|
||||
DirectShortestPathSearch(const PhantomNodes &phantom_nodes) const final override;
|
||||
InternalRouteResult DirectShortestPathSearch(
|
||||
const PhantomEndpointCandidates &endpoint_candidates) const final override;
|
||||
|
||||
virtual std::pair<std::vector<EdgeDuration>, std::vector<EdgeDistance>>
|
||||
ManyToManySearch(const std::vector<PhantomNode> &phantom_nodes,
|
||||
std::pair<std::vector<EdgeDuration>, std::vector<EdgeDistance>>
|
||||
ManyToManySearch(const std::vector<PhantomNodeCandidates> &candidates_list,
|
||||
const std::vector<std::size_t> &source_indices,
|
||||
const std::vector<std::size_t> &target_indices,
|
||||
const bool calculate_distance) const final override;
|
||||
@ -150,28 +150,27 @@ template <typename Algorithm> class RoutingAlgorithms final : public RoutingAlgo
|
||||
};
|
||||
|
||||
template <typename Algorithm>
|
||||
InternalManyRoutesResult
|
||||
RoutingAlgorithms<Algorithm>::AlternativePathSearch(const PhantomNodes &phantom_node_pair,
|
||||
unsigned number_of_alternatives) const
|
||||
InternalManyRoutesResult RoutingAlgorithms<Algorithm>::AlternativePathSearch(
|
||||
const PhantomEndpointCandidates &endpoint_candidates, unsigned number_of_alternatives) const
|
||||
{
|
||||
return routing_algorithms::alternativePathSearch(
|
||||
heaps, *facade, phantom_node_pair, number_of_alternatives);
|
||||
heaps, *facade, endpoint_candidates, number_of_alternatives);
|
||||
}
|
||||
|
||||
template <typename Algorithm>
|
||||
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
|
||||
{
|
||||
return routing_algorithms::shortestPathSearch(
|
||||
heaps, *facade, phantom_node_pair, continue_straight_at_waypoint);
|
||||
heaps, *facade, waypoint_candidates, continue_straight_at_waypoint);
|
||||
}
|
||||
|
||||
template <typename Algorithm>
|
||||
InternalRouteResult
|
||||
RoutingAlgorithms<Algorithm>::DirectShortestPathSearch(const PhantomNodes &phantom_nodes) const
|
||||
InternalRouteResult RoutingAlgorithms<Algorithm>::DirectShortestPathSearch(
|
||||
const PhantomEndpointCandidates &endpoint_candidates) const
|
||||
{
|
||||
return routing_algorithms::directShortestPathSearch(heaps, *facade, phantom_nodes);
|
||||
return routing_algorithms::directShortestPathSearch(heaps, *facade, endpoint_candidates);
|
||||
}
|
||||
|
||||
template <typename Algorithm>
|
||||
@ -193,30 +192,31 @@ inline routing_algorithms::SubMatchingList RoutingAlgorithms<Algorithm>::MapMatc
|
||||
|
||||
template <typename Algorithm>
|
||||
std::pair<std::vector<EdgeDuration>, std::vector<EdgeDistance>>
|
||||
RoutingAlgorithms<Algorithm>::ManyToManySearch(const std::vector<PhantomNode> &phantom_nodes,
|
||||
const std::vector<std::size_t> &_source_indices,
|
||||
const std::vector<std::size_t> &_target_indices,
|
||||
const bool calculate_distance) const
|
||||
RoutingAlgorithms<Algorithm>::ManyToManySearch(
|
||||
const std::vector<PhantomNodeCandidates> &candidates_list,
|
||||
const std::vector<std::size_t> &_source_indices,
|
||||
const std::vector<std::size_t> &_target_indices,
|
||||
const bool calculate_distance) const
|
||||
{
|
||||
BOOST_ASSERT(!phantom_nodes.empty());
|
||||
BOOST_ASSERT(!candidates_list.empty());
|
||||
|
||||
auto source_indices = _source_indices;
|
||||
auto target_indices = _target_indices;
|
||||
|
||||
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);
|
||||
}
|
||||
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);
|
||||
}
|
||||
|
||||
return routing_algorithms::manyToManySearch(heaps,
|
||||
*facade,
|
||||
phantom_nodes,
|
||||
candidates_list,
|
||||
std::move(source_indices),
|
||||
std::move(target_indices),
|
||||
calculate_distance);
|
||||
|
@ -18,12 +18,12 @@ namespace routing_algorithms
|
||||
|
||||
InternalManyRoutesResult alternativePathSearch(SearchEngineData<ch::Algorithm> &search_engine_data,
|
||||
const DataFacade<ch::Algorithm> &facade,
|
||||
const PhantomNodes &phantom_node_pair,
|
||||
const PhantomEndpointCandidates &endpoint_candidates,
|
||||
unsigned number_of_alternatives);
|
||||
|
||||
InternalManyRoutesResult alternativePathSearch(SearchEngineData<mld::Algorithm> &search_engine_data,
|
||||
const DataFacade<mld::Algorithm> &facade,
|
||||
const PhantomNodes &phantom_node_pair,
|
||||
const PhantomEndpointCandidates &endpoint_candidates,
|
||||
unsigned number_of_alternatives);
|
||||
|
||||
} // namespace routing_algorithms
|
||||
|
@ -24,7 +24,7 @@ namespace routing_algorithms
|
||||
template <typename Algorithm>
|
||||
InternalRouteResult directShortestPathSearch(SearchEngineData<Algorithm> &engine_working_data,
|
||||
const DataFacade<Algorithm> &facade,
|
||||
const PhantomNodes &phantom_nodes);
|
||||
const PhantomEndpointCandidates &endpoint_candidates);
|
||||
|
||||
} // namespace routing_algorithms
|
||||
} // namespace engine
|
||||
|
@ -94,7 +94,7 @@ template <typename Algorithm>
|
||||
std::pair<std::vector<EdgeDuration>, std::vector<EdgeDistance>>
|
||||
manyToManySearch(SearchEngineData<Algorithm> &engine_working_data,
|
||||
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> &target_indices,
|
||||
const bool calculate_distance);
|
||||
|
@ -34,20 +34,12 @@ namespace engine
|
||||
|
||||
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);
|
||||
bool needsLoopBackwards(const PhantomNode &source_phantom, const PhantomNode &target_phantom);
|
||||
|
||||
bool needsLoopForward(const PhantomNodes &phantoms);
|
||||
bool needsLoopBackwards(const PhantomNodes &phantoms);
|
||||
|
||||
template <typename Heap>
|
||||
void insertNodesInHeaps(Heap &forward_heap, Heap &reverse_heap, const PhantomNodes &nodes)
|
||||
namespace details
|
||||
{
|
||||
template <typename Heap>
|
||||
void insertSourceInForwardHeap(Heap &forward_heap, const PhantomNode &source)
|
||||
{
|
||||
const auto &source = nodes.source_phantom;
|
||||
if (source.IsValidForwardSource())
|
||||
{
|
||||
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.reverse_segment_id.id);
|
||||
}
|
||||
}
|
||||
|
||||
const auto &target = nodes.target_phantom;
|
||||
template <typename Heap>
|
||||
void insertTargetInReverseHeap(Heap &reverse_heap, const PhantomNode &target)
|
||||
{
|
||||
if (target.IsValidForwardTarget())
|
||||
{
|
||||
reverse_heap.Insert(target.forward_segment_id.id,
|
||||
@ -77,52 +72,104 @@ void insertNodesInHeaps(Heap &forward_heap, Heap &reverse_heap, const PhantomNod
|
||||
target.reverse_segment_id.id);
|
||||
}
|
||||
}
|
||||
} // namespace details
|
||||
static constexpr bool FORWARD_DIRECTION = true;
|
||||
static constexpr bool REVERSE_DIRECTION = false;
|
||||
|
||||
template <typename ManyToManyQueryHeap>
|
||||
void insertSourceInHeap(ManyToManyQueryHeap &heap, const PhantomNode &phantom_node)
|
||||
// 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 (phantom_node.IsValidForwardSource())
|
||||
// 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)
|
||||
{
|
||||
heap.Insert(phantom_node.forward_segment_id.id,
|
||||
-phantom_node.GetForwardWeightPlusOffset(),
|
||||
{phantom_node.forward_segment_id.id,
|
||||
-phantom_node.GetForwardDuration(),
|
||||
-phantom_node.GetForwardDistance()});
|
||||
details::insertSourceInForwardHeap(forward_heap, source);
|
||||
}
|
||||
if (phantom_node.IsValidReverseSource())
|
||||
|
||||
for (const auto &target : endpoint_candidates.target_phantoms)
|
||||
{
|
||||
heap.Insert(phantom_node.reverse_segment_id.id,
|
||||
-phantom_node.GetReverseWeightPlusOffset(),
|
||||
{phantom_node.reverse_segment_id.id,
|
||||
-phantom_node.GetReverseDuration(),
|
||||
-phantom_node.GetReverseDistance()});
|
||||
details::insertTargetInReverseHeap(reverse_heap, target);
|
||||
}
|
||||
}
|
||||
|
||||
template <typename ManyToManyQueryHeap>
|
||||
void insertTargetInHeap(ManyToManyQueryHeap &heap, const PhantomNode &phantom_node)
|
||||
void insertSourceInHeap(ManyToManyQueryHeap &heap, const PhantomNodeCandidates &source_candidates)
|
||||
{
|
||||
if (phantom_node.IsValidForwardTarget())
|
||||
for (const auto &phantom_node : source_candidates)
|
||||
{
|
||||
heap.Insert(phantom_node.forward_segment_id.id,
|
||||
phantom_node.GetForwardWeightPlusOffset(),
|
||||
{phantom_node.forward_segment_id.id,
|
||||
phantom_node.GetForwardDuration(),
|
||||
phantom_node.GetForwardDistance()});
|
||||
if (phantom_node.IsValidForwardSource())
|
||||
{
|
||||
heap.Insert(phantom_node.forward_segment_id.id,
|
||||
-phantom_node.GetForwardWeightPlusOffset(),
|
||||
{phantom_node.forward_segment_id.id,
|
||||
-phantom_node.GetForwardDuration(),
|
||||
-phantom_node.GetForwardDistance()});
|
||||
}
|
||||
if (phantom_node.IsValidReverseSource())
|
||||
{
|
||||
heap.Insert(phantom_node.reverse_segment_id.id,
|
||||
-phantom_node.GetReverseWeightPlusOffset(),
|
||||
{phantom_node.reverse_segment_id.id,
|
||||
-phantom_node.GetReverseDuration(),
|
||||
-phantom_node.GetReverseDistance()});
|
||||
}
|
||||
}
|
||||
if (phantom_node.IsValidReverseTarget())
|
||||
}
|
||||
|
||||
template <typename ManyToManyQueryHeap>
|
||||
void insertTargetInHeap(ManyToManyQueryHeap &heap, const PhantomNodeCandidates &target_candidates)
|
||||
{
|
||||
for (const auto &phantom_node : target_candidates)
|
||||
{
|
||||
heap.Insert(phantom_node.reverse_segment_id.id,
|
||||
phantom_node.GetReverseWeightPlusOffset(),
|
||||
{phantom_node.reverse_segment_id.id,
|
||||
phantom_node.GetReverseDuration(),
|
||||
phantom_node.GetReverseDistance()});
|
||||
if (phantom_node.IsValidForwardTarget())
|
||||
{
|
||||
heap.Insert(phantom_node.forward_segment_id.id,
|
||||
phantom_node.GetForwardWeightPlusOffset(),
|
||||
{phantom_node.forward_segment_id.id,
|
||||
phantom_node.GetForwardDuration(),
|
||||
phantom_node.GetForwardDistance()});
|
||||
}
|
||||
if (phantom_node.IsValidReverseTarget())
|
||||
{
|
||||
heap.Insert(phantom_node.reverse_segment_id.id,
|
||||
phantom_node.GetReverseWeightPlusOffset(),
|
||||
{phantom_node.reverse_segment_id.id,
|
||||
phantom_node.GetReverseDuration(),
|
||||
phantom_node.GetReverseDistance()});
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
template <typename FacadeT>
|
||||
void annotatePath(const FacadeT &facade,
|
||||
const PhantomNodes &phantom_node_pair,
|
||||
const PhantomEndpoints &endpoints,
|
||||
const std::vector<NodeID> &unpacked_nodes,
|
||||
const std::vector<EdgeID> &unpacked_edges,
|
||||
std::vector<PathData> &unpacked_path)
|
||||
@ -133,14 +180,14 @@ void annotatePath(const FacadeT &facade,
|
||||
const auto source_node_id = unpacked_nodes.front();
|
||||
const auto target_node_id = unpacked_nodes.back();
|
||||
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 =
|
||||
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 ||
|
||||
phantom_node_pair.source_phantom.reverse_segment_id.id == source_node_id);
|
||||
BOOST_ASSERT(phantom_node_pair.target_phantom.forward_segment_id.id == target_node_id ||
|
||||
phantom_node_pair.target_phantom.reverse_segment_id.id == target_node_id);
|
||||
BOOST_ASSERT(endpoints.source_phantom.forward_segment_id.id == source_node_id ||
|
||||
endpoints.source_phantom.reverse_segment_id.id == source_node_id);
|
||||
BOOST_ASSERT(endpoints.target_phantom.forward_segment_id.id == target_node_id ||
|
||||
endpoints.target_phantom.reverse_segment_id.id == target_node_id);
|
||||
|
||||
// datastructures to hold extracted data from geometry
|
||||
std::vector<NodeID> id_vector;
|
||||
@ -180,8 +227,8 @@ void annotatePath(const FacadeT &facade,
|
||||
const auto geometry_index = facade.GetGeometryIndex(node_id);
|
||||
get_segment_geometry(geometry_index);
|
||||
|
||||
BOOST_ASSERT(id_vector.size() > 0);
|
||||
BOOST_ASSERT(datasource_vector.size() > 0);
|
||||
BOOST_ASSERT(!id_vector.empty());
|
||||
BOOST_ASSERT(!datasource_vector.empty());
|
||||
BOOST_ASSERT(weight_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;
|
||||
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)
|
||||
{
|
||||
segment_position = weight_vector.size() -
|
||||
phantom_node_pair.source_phantom.fwd_segment_position - 1;
|
||||
segment_position =
|
||||
weight_vector.size() - endpoints.source_phantom.fwd_segment_position - 1;
|
||||
}
|
||||
BOOST_ASSERT(segment_position >= 0);
|
||||
start_index = static_cast<std::size_t>(segment_position);
|
||||
@ -214,7 +261,7 @@ void annotatePath(const FacadeT &facade,
|
||||
datasource_vector[segment_idx],
|
||||
boost::none});
|
||||
}
|
||||
BOOST_ASSERT(unpacked_path.size() > 0);
|
||||
BOOST_ASSERT(!unpacked_path.empty());
|
||||
|
||||
const auto turn_duration = facade.GetDurationPenaltyForEdgeID(turn_id);
|
||||
const auto turn_weight = facade.GetWeightPenaltyForEdgeID(turn_id);
|
||||
@ -237,19 +284,17 @@ void annotatePath(const FacadeT &facade,
|
||||
{
|
||||
if (is_local_path)
|
||||
{
|
||||
start_index =
|
||||
weight_vector.size() - phantom_node_pair.source_phantom.fwd_segment_position - 1;
|
||||
start_index = weight_vector.size() - endpoints.source_phantom.fwd_segment_position - 1;
|
||||
}
|
||||
end_index =
|
||||
weight_vector.size() - phantom_node_pair.target_phantom.fwd_segment_position - 1;
|
||||
end_index = weight_vector.size() - endpoints.target_phantom.fwd_segment_position - 1;
|
||||
}
|
||||
else
|
||||
{
|
||||
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:
|
||||
@ -277,11 +322,11 @@ void annotatePath(const FacadeT &facade,
|
||||
if (!unpacked_path.empty())
|
||||
{
|
||||
const auto source_weight = start_traversed_in_reverse
|
||||
? phantom_node_pair.source_phantom.reverse_weight
|
||||
: phantom_node_pair.source_phantom.forward_weight;
|
||||
? endpoints.source_phantom.reverse_weight
|
||||
: endpoints.source_phantom.forward_weight;
|
||||
const auto source_duration = start_traversed_in_reverse
|
||||
? phantom_node_pair.source_phantom.reverse_duration
|
||||
: phantom_node_pair.source_phantom.forward_duration;
|
||||
? endpoints.source_phantom.reverse_duration
|
||||
: endpoints.source_phantom.forward_duration;
|
||||
// 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
|
||||
// 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>
|
||||
InternalRouteResult extractRoute(const DataFacade<AlgorithmT> &facade,
|
||||
const EdgeWeight weight,
|
||||
const PhantomNodes &phantom_nodes,
|
||||
const PhantomEndpointCandidates &endpoint_candidates,
|
||||
const std::vector<NodeID> &unpacked_nodes,
|
||||
const std::vector<EdgeID> &unpacked_edges)
|
||||
{
|
||||
InternalRouteResult raw_route_data;
|
||||
raw_route_data.segment_end_coordinates = {phantom_nodes};
|
||||
|
||||
// No path found for both target nodes?
|
||||
if (INVALID_EDGE_WEIGHT == weight)
|
||||
@ -371,15 +415,18 @@ InternalRouteResult extractRoute(const DataFacade<AlgorithmT> &facade,
|
||||
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.unpacked_path_segments.resize(1);
|
||||
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(
|
||||
(unpacked_nodes.back() != phantom_nodes.target_phantom.forward_segment_id.id));
|
||||
(unpacked_nodes.back() != phantom_endpoints.target_phantom.forward_segment_id.id));
|
||||
|
||||
annotatePath(facade,
|
||||
phantom_nodes,
|
||||
phantom_endpoints,
|
||||
unpacked_nodes,
|
||||
unpacked_edges,
|
||||
raw_route_data.unpacked_path_segments.front());
|
||||
|
@ -120,8 +120,8 @@ void routingStep(const DataFacade<Algorithm> &facade,
|
||||
NodeID &middle_node_id,
|
||||
EdgeWeight &upper_bound,
|
||||
EdgeWeight min_edge_offset,
|
||||
const bool force_loop_forward,
|
||||
const bool force_loop_reverse)
|
||||
const std::vector<NodeID> &force_loop_forward_nodes,
|
||||
const std::vector<NodeID> &force_loop_reverse_nodes)
|
||||
{
|
||||
auto heapNode = forward_heap.DeleteMinGetHeapNode();
|
||||
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;
|
||||
if (new_weight < upper_bound)
|
||||
{
|
||||
// if loops are forced, they are so at the source
|
||||
if ((force_loop_forward && heapNode.data.parent == heapNode.node) ||
|
||||
(force_loop_reverse && reverseHeapNode->data.parent == heapNode.node) ||
|
||||
if (force_loop(force_loop_forward_nodes, heapNode) ||
|
||||
force_loop(force_loop_reverse_nodes, heapNode) ||
|
||||
// in this case we are looking at a bi-directional way where the source
|
||||
// and target phantom are on the same edge based node
|
||||
new_weight < 0)
|
||||
@ -398,7 +397,7 @@ template <typename RandomIter, typename FacadeT>
|
||||
void unpackPath(const FacadeT &facade,
|
||||
RandomIter packed_path_begin,
|
||||
RandomIter packed_path_end,
|
||||
const PhantomNodes &phantom_nodes,
|
||||
const PhantomEndpoints &route_endpoints,
|
||||
std::vector<PathData> &unpacked_path)
|
||||
{
|
||||
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,
|
||||
SearchEngineData<Algorithm>::QueryHeap &forward_heap,
|
||||
SearchEngineData<Algorithm>::QueryHeap &reverse_heap,
|
||||
std::int32_t &weight,
|
||||
EdgeWeight &weight,
|
||||
std::vector<NodeID> &packed_leg,
|
||||
const bool force_loop_forward,
|
||||
const bool force_loop_reverse,
|
||||
const PhantomNodes &phantom_nodes,
|
||||
const int duration_upper_bound = INVALID_EDGE_WEIGHT);
|
||||
const std::vector<NodeID> &force_loop_forward_node,
|
||||
const std::vector<NodeID> &force_loop_reverse_node,
|
||||
const EdgeWeight 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
|
||||
// If heaps should be adjusted to be initialized outside of this function,
|
||||
|
@ -33,24 +33,75 @@ namespace
|
||||
template <typename MultiLevelPartition>
|
||||
inline LevelID getNodeQueryLevel(const MultiLevelPartition &partition,
|
||||
NodeID node,
|
||||
const PhantomNodes &phantom_nodes)
|
||||
const PhantomNode &source,
|
||||
const PhantomNode &target)
|
||||
{
|
||||
auto level = [&partition, node](const SegmentID &source, const SegmentID &target) {
|
||||
if (source.enabled && target.enabled)
|
||||
return partition.GetQueryLevel(source.id, target.id, node);
|
||||
return INVALID_LEVEL_ID;
|
||||
};
|
||||
return std::min(std::min(level(phantom_nodes.source_phantom.forward_segment_id,
|
||||
phantom_nodes.target_phantom.forward_segment_id),
|
||||
level(phantom_nodes.source_phantom.forward_segment_id,
|
||||
phantom_nodes.target_phantom.reverse_segment_id)),
|
||||
std::min(level(phantom_nodes.source_phantom.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)));
|
||||
|
||||
return std::min(std::min(level(source.forward_segment_id, target.forward_segment_id),
|
||||
level(source.forward_segment_id, target.reverse_segment_id)),
|
||||
std::min(level(source.reverse_segment_id, target.forward_segment_id),
|
||||
level(source.reverse_segment_id, target.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):
|
||||
// * use the fixed level for queries
|
||||
@ -72,17 +123,23 @@ inline bool checkParentCellRestriction(CellID cell, LevelID, CellID parent)
|
||||
template <typename MultiLevelPartition>
|
||||
inline LevelID getNodeQueryLevel(const MultiLevelPartition &partition,
|
||||
const NodeID node,
|
||||
const PhantomNode &phantom_node)
|
||||
const PhantomNodeCandidates &candidates)
|
||||
{
|
||||
auto highest_diffrent_level = [&partition, node](const SegmentID &phantom_node) {
|
||||
if (phantom_node.enabled)
|
||||
return partition.GetHighestDifferentLevel(phantom_node.id, node);
|
||||
return INVALID_LEVEL_ID;
|
||||
auto highest_different_level = [&partition, node](const SegmentID &segment) {
|
||||
return segment.enabled ? partition.GetHighestDifferentLevel(segment.id, node)
|
||||
: INVALID_LEVEL_ID;
|
||||
};
|
||||
|
||||
const auto node_level = std::min(highest_diffrent_level(phantom_node.forward_segment_id),
|
||||
highest_diffrent_level(phantom_node.reverse_segment_id));
|
||||
|
||||
auto node_level =
|
||||
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;
|
||||
}
|
||||
|
||||
@ -92,31 +149,17 @@ inline LevelID getNodeQueryLevel(const MultiLevelPartition &partition,
|
||||
template <typename MultiLevelPartition>
|
||||
inline LevelID getNodeQueryLevel(const MultiLevelPartition &partition,
|
||||
NodeID node,
|
||||
const std::vector<PhantomNode> &phantom_nodes,
|
||||
const std::vector<PhantomNodeCandidates> &candidates_list,
|
||||
const std::size_t phantom_index,
|
||||
const std::vector<std::size_t> &phantom_indices)
|
||||
{
|
||||
auto min_level = [&partition, node](const PhantomNode &phantom_node) {
|
||||
const auto &forward_segment = phantom_node.forward_segment_id;
|
||||
const auto forward_level =
|
||||
forward_segment.enabled ? partition.GetHighestDifferentLevel(node, forward_segment.id)
|
||||
: INVALID_LEVEL_ID;
|
||||
|
||||
const auto &reverse_segment = phantom_node.reverse_segment_id;
|
||||
const auto reverse_level =
|
||||
reverse_segment.enabled ? partition.GetHighestDifferentLevel(node, reverse_segment.id)
|
||||
: INVALID_LEVEL_ID;
|
||||
|
||||
return std::min(forward_level, reverse_level);
|
||||
};
|
||||
|
||||
// Get minimum level over all phantoms of the highest different level with respect to node
|
||||
// This is equivalent to min_{∀ source, target} partition.GetQueryLevel(source, node, target)
|
||||
auto result = min_level(phantom_nodes[phantom_index]);
|
||||
for (const auto &index : phantom_indices)
|
||||
{
|
||||
result = std::min(result, min_level(phantom_nodes[index]));
|
||||
}
|
||||
auto init = getNodeQueryLevel(partition, node, candidates_list[phantom_index]);
|
||||
auto result = std::accumulate(
|
||||
phantom_indices.begin(), phantom_indices.end(), init, [&](LevelID level, size_t index) {
|
||||
return std::min(level, getNodeQueryLevel(partition, node, candidates_list[index]));
|
||||
});
|
||||
return result;
|
||||
}
|
||||
} // namespace
|
||||
@ -229,7 +272,7 @@ template <bool DIRECTION, typename Algorithm, typename... Args>
|
||||
void relaxOutgoingEdges(const DataFacade<Algorithm> &facade,
|
||||
typename SearchEngineData<Algorithm>::QueryHeap &forward_heap,
|
||||
const typename SearchEngineData<Algorithm>::QueryHeap::HeapNode &heapNode,
|
||||
Args... args)
|
||||
const Args &... args)
|
||||
{
|
||||
const auto &partition = facade.GetMultiLevelPartition();
|
||||
const auto &cells = facade.GetCellStorage();
|
||||
@ -344,9 +387,9 @@ void routingStep(const DataFacade<Algorithm> &facade,
|
||||
typename SearchEngineData<Algorithm>::QueryHeap &reverse_heap,
|
||||
NodeID &middle_node,
|
||||
EdgeWeight &path_upper_bound,
|
||||
const bool force_loop_forward,
|
||||
const bool force_loop_reverse,
|
||||
Args... args)
|
||||
const std::vector<NodeID> &force_loop_forward_nodes,
|
||||
const std::vector<NodeID> &force_loop_reverse_nodes,
|
||||
const Args &... args)
|
||||
{
|
||||
const auto heapNode = forward_heap.DeleteMinGetHeapNode();
|
||||
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
|
||||
// backward direction (there is no need to force loops in MLD but in CH)
|
||||
if (!(force_loop_forward && heapNode.data.parent == heapNode.node) &&
|
||||
!(force_loop_reverse && reverseHeapNode->data.parent == heapNode.node) &&
|
||||
(path_weight >= 0) && (path_weight < path_upper_bound))
|
||||
if (!force_loop(force_loop_forward_nodes, heapNode) &&
|
||||
!force_loop(force_loop_reverse_nodes, heapNode) && (path_weight >= 0) &&
|
||||
(path_weight < path_upper_bound))
|
||||
{
|
||||
middle_node = heapNode.node;
|
||||
path_upper_bound = path_weight;
|
||||
@ -393,10 +436,10 @@ UnpackedPath search(SearchEngineData<Algorithm> &engine_working_data,
|
||||
const DataFacade<Algorithm> &facade,
|
||||
typename SearchEngineData<Algorithm>::QueryHeap &forward_heap,
|
||||
typename SearchEngineData<Algorithm>::QueryHeap &reverse_heap,
|
||||
const bool force_loop_forward,
|
||||
const bool force_loop_reverse,
|
||||
const std::vector<NodeID> &force_loop_forward_nodes,
|
||||
const std::vector<NodeID> &force_loop_reverse_nodes,
|
||||
EdgeWeight weight_upper_bound,
|
||||
Args... args)
|
||||
const Args &... args)
|
||||
{
|
||||
if (forward_heap.Empty() || reverse_heap.Empty())
|
||||
{
|
||||
@ -423,8 +466,8 @@ UnpackedPath search(SearchEngineData<Algorithm> &engine_working_data,
|
||||
reverse_heap,
|
||||
middle,
|
||||
weight,
|
||||
force_loop_forward,
|
||||
force_loop_reverse,
|
||||
force_loop_forward_nodes,
|
||||
force_loop_reverse_nodes,
|
||||
args...);
|
||||
if (!forward_heap.Empty())
|
||||
forward_heap_min = forward_heap.MinKey();
|
||||
@ -436,8 +479,8 @@ UnpackedPath search(SearchEngineData<Algorithm> &engine_working_data,
|
||||
forward_heap,
|
||||
middle,
|
||||
weight,
|
||||
force_loop_reverse,
|
||||
force_loop_forward,
|
||||
force_loop_reverse_nodes,
|
||||
force_loop_forward_nodes,
|
||||
args...);
|
||||
if (!reverse_heap.Empty())
|
||||
reverse_heap_min = reverse_heap.MinKey();
|
||||
@ -494,15 +537,16 @@ UnpackedPath search(SearchEngineData<Algorithm> &engine_working_data,
|
||||
EdgeWeight subpath_weight;
|
||||
std::vector<NodeID> subpath_nodes;
|
||||
std::vector<EdgeID> subpath_edges;
|
||||
std::tie(subpath_weight, subpath_nodes, subpath_edges) = search(engine_working_data,
|
||||
facade,
|
||||
forward_heap,
|
||||
reverse_heap,
|
||||
force_loop_forward,
|
||||
force_loop_reverse,
|
||||
INVALID_EDGE_WEIGHT,
|
||||
sublevel,
|
||||
parent_cell_id);
|
||||
std::tie(subpath_weight, subpath_nodes, subpath_edges) =
|
||||
search(engine_working_data,
|
||||
facade,
|
||||
forward_heap,
|
||||
reverse_heap,
|
||||
force_loop_forward_nodes,
|
||||
force_loop_reverse_nodes,
|
||||
INVALID_EDGE_WEIGHT,
|
||||
sublevel,
|
||||
parent_cell_id);
|
||||
BOOST_ASSERT(!subpath_edges.empty());
|
||||
BOOST_ASSERT(subpath_nodes.size() > 1);
|
||||
BOOST_ASSERT(subpath_nodes.front() == source);
|
||||
@ -517,16 +561,16 @@ UnpackedPath search(SearchEngineData<Algorithm> &engine_working_data,
|
||||
}
|
||||
|
||||
// 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,
|
||||
const DataFacade<Algorithm> &facade,
|
||||
typename SearchEngineData<Algorithm>::QueryHeap &forward_heap,
|
||||
typename SearchEngineData<Algorithm>::QueryHeap &reverse_heap,
|
||||
EdgeWeight &weight,
|
||||
std::vector<NodeID> &unpacked_nodes,
|
||||
const bool force_loop_forward,
|
||||
const bool force_loop_reverse,
|
||||
const PhantomNodes &phantom_nodes,
|
||||
const std::vector<NodeID> &force_loop_forward_node,
|
||||
const std::vector<NodeID> &force_loop_reverse_node,
|
||||
const PhantomEndpointT &endpoints,
|
||||
const EdgeWeight weight_upper_bound = INVALID_EDGE_WEIGHT)
|
||||
{
|
||||
// TODO: change search calling interface to use unpacked_edges result
|
||||
@ -534,10 +578,10 @@ inline void search(SearchEngineData<Algorithm> &engine_working_data,
|
||||
facade,
|
||||
forward_heap,
|
||||
reverse_heap,
|
||||
force_loop_forward,
|
||||
force_loop_reverse,
|
||||
force_loop_forward_node,
|
||||
force_loop_reverse_node,
|
||||
weight_upper_bound,
|
||||
phantom_nodes);
|
||||
endpoints);
|
||||
}
|
||||
|
||||
// TODO: refactor CH-related stub to use unpacked_edges
|
||||
@ -545,7 +589,7 @@ template <typename RandomIter, typename FacadeT>
|
||||
void unpackPath(const FacadeT &facade,
|
||||
RandomIter packed_path_begin,
|
||||
RandomIter packed_path_end,
|
||||
const PhantomNodes &phantom_nodes,
|
||||
const PhantomEndpoints &route_endpoints,
|
||||
std::vector<PathData> &unpacked_path)
|
||||
{
|
||||
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>
|
||||
@ -583,8 +627,8 @@ double getNetworkDistance(SearchEngineData<Algorithm> &engine_working_data,
|
||||
forward_heap.Clear();
|
||||
reverse_heap.Clear();
|
||||
|
||||
const PhantomNodes phantom_nodes{source_phantom, target_phantom};
|
||||
insertNodesInHeaps(forward_heap, reverse_heap, phantom_nodes);
|
||||
const PhantomEndpoints endpoints{source_phantom, target_phantom};
|
||||
insertNodesInHeaps(forward_heap, reverse_heap, endpoints);
|
||||
|
||||
EdgeWeight weight = INVALID_EDGE_WEIGHT;
|
||||
std::vector<NodeID> unpacked_nodes;
|
||||
@ -593,10 +637,10 @@ double getNetworkDistance(SearchEngineData<Algorithm> &engine_working_data,
|
||||
facade,
|
||||
forward_heap,
|
||||
reverse_heap,
|
||||
DO_NOT_FORCE_LOOPS,
|
||||
DO_NOT_FORCE_LOOPS,
|
||||
{},
|
||||
{},
|
||||
weight_upper_bound,
|
||||
phantom_nodes);
|
||||
endpoints);
|
||||
|
||||
if (weight == INVALID_EDGE_WEIGHT)
|
||||
{
|
||||
@ -605,7 +649,7 @@ double getNetworkDistance(SearchEngineData<Algorithm> &engine_working_data,
|
||||
|
||||
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);
|
||||
}
|
||||
|
@ -14,10 +14,11 @@ namespace routing_algorithms
|
||||
{
|
||||
|
||||
template <typename Algorithm>
|
||||
InternalRouteResult shortestPathSearch(SearchEngineData<Algorithm> &engine_working_data,
|
||||
const DataFacade<Algorithm> &facade,
|
||||
const std::vector<PhantomNodes> &phantom_nodes_vector,
|
||||
const boost::optional<bool> continue_straight_at_waypoint);
|
||||
InternalRouteResult
|
||||
shortestPathSearch(SearchEngineData<Algorithm> &engine_working_data,
|
||||
const DataFacade<Algorithm> &facade,
|
||||
const std::vector<PhantomNodeCandidates> &waypoint_candidates,
|
||||
const boost::optional<bool> continue_straight_at_waypoint);
|
||||
|
||||
} // namespace routing_algorithms
|
||||
} // namespace engine
|
||||
|
File diff suppressed because it is too large
Load Diff
@ -78,10 +78,17 @@ struct BaseParametersGrammar : boost::spirit::qi::grammar<Iterator, Signature>
|
||||
: BaseParametersGrammar::base_type(root_rule)
|
||||
{
|
||||
const auto add_hint = [](engine::api::BaseParameters &base_parameters,
|
||||
const boost::optional<std::string> &hint_string) {
|
||||
if (hint_string)
|
||||
const std::vector<std::string> &hint_strings) {
|
||||
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
|
||||
{
|
||||
@ -145,10 +152,11 @@ struct BaseParametersGrammar : boost::spirit::qi::grammar<Iterator, Signature>
|
||||
(-(qi::double_ | unlimited_rule) %
|
||||
';')[ph::bind(&engine::api::BaseParameters::radiuses, qi::_r1) = qi::_1];
|
||||
|
||||
hints_rule = qi::lit("hints=") >
|
||||
(-qi::as_string[qi::repeat(engine::ENCODED_HINT_SIZE)[base64_char]])[ph::bind(
|
||||
add_hint, qi::_r1, qi::_1)] %
|
||||
';';
|
||||
hints_rule =
|
||||
qi::lit("hints=") >
|
||||
(*qi::as_string[qi::repeat(engine::ENCODED_SEGMENT_HINT_SIZE)[base64_char]])[ph::bind(
|
||||
add_hint, qi::_r1, qi::_1)] %
|
||||
';';
|
||||
|
||||
generate_hints_rule =
|
||||
qi::lit("generate_hints=") >
|
||||
|
@ -68,7 +68,7 @@ write(storage::tar::FileWriter &writer,
|
||||
|
||||
/***
|
||||
* 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!
|
||||
*/
|
||||
|
||||
@ -556,8 +556,8 @@ class StaticRTree
|
||||
}
|
||||
|
||||
// Override filter and terminator for the desired behaviour.
|
||||
std::vector<EdgeDataT> Nearest(const Coordinate input_coordinate,
|
||||
const std::size_t max_results) const
|
||||
std::vector<CandidateSegment> Nearest(const Coordinate input_coordinate,
|
||||
const std::size_t max_results) const
|
||||
{
|
||||
return Nearest(
|
||||
input_coordinate,
|
||||
@ -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>
|
||||
std::vector<EdgeDataT> Nearest(const Coordinate input_coordinate,
|
||||
const FilterT filter,
|
||||
const TerminationT terminate) const
|
||||
std::vector<CandidateSegment> Nearest(const Coordinate input_coordinate,
|
||||
const FilterT filter,
|
||||
const TerminationT terminate) const
|
||||
{
|
||||
std::vector<EdgeDataT> results;
|
||||
std::vector<CandidateSegment> results;
|
||||
auto projected_coordinate = web_mercator::fromWGS84(input_coordinate);
|
||||
Coordinate fixed_projected_coordinate{projected_coordinate};
|
||||
// initialize queue with root element
|
||||
@ -603,10 +603,10 @@ class StaticRTree
|
||||
}
|
||||
else
|
||||
{ // current candidate is an actual road segment
|
||||
// We deliberatly make a copy here, we mutate the value below
|
||||
auto edge_data = m_objects[current_query_node.segment_index];
|
||||
const auto ¤t_candidate =
|
||||
CandidateSegment{current_query_node.fixed_projected_coordinate, edge_data};
|
||||
const auto &edge_data = m_objects[current_query_node.segment_index];
|
||||
// We deliberately make an edge data copy here, we mutate the value below
|
||||
CandidateSegment current_candidate{current_query_node.fixed_projected_coordinate,
|
||||
edge_data};
|
||||
|
||||
// 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
|
||||
@ -621,11 +621,11 @@ class StaticRTree
|
||||
{
|
||||
continue;
|
||||
}
|
||||
edge_data.forward_segment_id.enabled &= use_segment.first;
|
||||
edge_data.reverse_segment_id.enabled &= use_segment.second;
|
||||
current_candidate.data.forward_segment_id.enabled &= use_segment.first;
|
||||
current_candidate.data.reverse_segment_id.enabled &= use_segment.second;
|
||||
|
||||
// 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
|
||||
* priority queue using their distance from the search coordinate as the
|
||||
* 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).
|
||||
*/
|
||||
template <class QueueT>
|
||||
|
@ -239,10 +239,10 @@ makeWaypoint(const util::Coordinate &location, const double &distance, std::stri
|
||||
util::json::Object makeWaypoint(const util::Coordinate &location,
|
||||
const double &distance,
|
||||
std::string name,
|
||||
const Hint &hint)
|
||||
const Hint &location_hints)
|
||||
{
|
||||
auto waypoint = makeWaypoint(location, distance, std::move(name));
|
||||
waypoint.values["hint"] = hint.ToBase64();
|
||||
waypoint.values["hint"] = location_hints.ToBase64();
|
||||
return waypoint;
|
||||
}
|
||||
|
||||
|
@ -3,10 +3,10 @@
|
||||
#include "engine/datafacade/datafacade_base.hpp"
|
||||
|
||||
#include <boost/assert.hpp>
|
||||
#include <boost/unordered_set.hpp>
|
||||
|
||||
#include <algorithm>
|
||||
#include <iterator>
|
||||
#include <ostream>
|
||||
#include <tuple>
|
||||
|
||||
namespace osrm
|
||||
@ -14,8 +14,8 @@ namespace osrm
|
||||
namespace engine
|
||||
{
|
||||
|
||||
bool Hint::IsValid(const util::Coordinate new_input_coordinates,
|
||||
const datafacade::BaseDataFacade &facade) const
|
||||
bool SegmentHint::IsValid(const util::Coordinate new_input_coordinates,
|
||||
const datafacade::BaseDataFacade &facade) const
|
||||
{
|
||||
auto is_same_input_coordinate = new_input_coordinates.lon == phantom.input_location.lon &&
|
||||
new_input_coordinates.lat == phantom.input_location.lat;
|
||||
@ -25,7 +25,7 @@ bool Hint::IsValid(const util::Coordinate new_input_coordinates,
|
||||
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);
|
||||
|
||||
@ -36,9 +36,9 @@ std::string Hint::ToBase64() const
|
||||
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
|
||||
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), '_', '/');
|
||||
|
||||
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);
|
||||
}
|
||||
|
||||
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 osrm
|
||||
|
@ -4,21 +4,16 @@
|
||||
#include "engine/api/match_api.hpp"
|
||||
#include "engine/api/match_parameters.hpp"
|
||||
#include "engine/api/match_parameters_tidy.hpp"
|
||||
#include "engine/map_matching/bayes_classifier.hpp"
|
||||
#include "engine/map_matching/sub_matching.hpp"
|
||||
#include "util/coordinate_calculation.hpp"
|
||||
#include "util/integer_range.hpp"
|
||||
#include "util/json_util.hpp"
|
||||
#include "util/string_util.hpp"
|
||||
|
||||
#include <cstdlib>
|
||||
|
||||
#include <algorithm>
|
||||
#include <functional>
|
||||
#include <iterator>
|
||||
#include <memory>
|
||||
#include <set>
|
||||
#include <string>
|
||||
#include <vector>
|
||||
|
||||
namespace osrm
|
||||
@ -28,7 +23,7 @@ namespace engine
|
||||
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,
|
||||
MatchPlugin::CandidateLists &candidates_lists)
|
||||
{
|
||||
@ -272,20 +267,26 @@ Status MatchPlugin::HandleRequest(const RoutingAlgorithmsInterface &algorithms,
|
||||
|
||||
// FIXME we only run this to obtain the geometry
|
||||
// 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)
|
||||
{
|
||||
current_phantom_node_pair.source_phantom = sub_matchings[index].nodes[i];
|
||||
current_phantom_node_pair.target_phantom = sub_matchings[index].nodes[i + 1];
|
||||
BOOST_ASSERT(current_phantom_node_pair.source_phantom.IsValid());
|
||||
BOOST_ASSERT(current_phantom_node_pair.target_phantom.IsValid());
|
||||
sub_routes[index].segment_end_coordinates.emplace_back(current_phantom_node_pair);
|
||||
PhantomEndpoints current_endpoints{sub_matchings[index].nodes[i],
|
||||
sub_matchings[index].nodes[i + 1]};
|
||||
BOOST_ASSERT(current_endpoints.source_phantom.IsValid());
|
||||
BOOST_ASSERT(current_endpoints.target_phantom.IsValid());
|
||||
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
|
||||
// we split the phantom nodes anyway and only have bi-directional phantom nodes for
|
||||
// possible uturns
|
||||
sub_routes[index] =
|
||||
algorithms.ShortestPathSearch(sub_routes[index].segment_end_coordinates, {false});
|
||||
sub_routes[index] = algorithms.ShortestPathSearch(waypoint_candidates, {false});
|
||||
BOOST_ASSERT(sub_routes[index].shortest_path_weight != INVALID_EDGE_WEIGHT);
|
||||
if (collapse_legs)
|
||||
{
|
||||
|
@ -1,10 +1,7 @@
|
||||
#include "engine/plugins/nearest.hpp"
|
||||
#include "engine/api/nearest_api.hpp"
|
||||
#include "engine/api/nearest_parameters.hpp"
|
||||
#include "engine/phantom_node.hpp"
|
||||
#include "util/integer_range.hpp"
|
||||
|
||||
#include <cstddef>
|
||||
#include <string>
|
||||
|
||||
#include <boost/assert.hpp>
|
||||
|
@ -2,17 +2,11 @@
|
||||
|
||||
#include "engine/api/table_api.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/json_container.hpp"
|
||||
#include "util/string_util.hpp"
|
||||
|
||||
#include <cstdlib>
|
||||
|
||||
#include <algorithm>
|
||||
#include <memory>
|
||||
#include <string>
|
||||
#include <vector>
|
||||
|
||||
#include <boost/assert.hpp>
|
||||
@ -47,7 +41,7 @@ Status TablePlugin::HandleRequest(const RoutingAlgorithmsInterface &algorithms,
|
||||
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(
|
||||
"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);
|
||||
}
|
||||
|
||||
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_duration = params.annotations & api::TableParameters::AnnotationsType::Duration;
|
||||
@ -117,9 +111,11 @@ Status TablePlugin::HandleRequest(const RoutingAlgorithmsInterface &algorithms,
|
||||
params.fallback_coordinate_type ==
|
||||
api::TableParameters::FallbackCoordinateType::Input
|
||||
? util::coordinate_calculation::greatCircleDistance(
|
||||
source.input_location, destination.input_location)
|
||||
candidatesInputLocation(source),
|
||||
candidatesInputLocation(destination))
|
||||
: util::coordinate_calculation::greatCircleDistance(
|
||||
source.location, destination.location);
|
||||
candidatesSnappedLocation(source),
|
||||
candidatesSnappedLocation(destination));
|
||||
|
||||
result_tables_pair.first[table_index] =
|
||||
distance_estimate / (double)params.fallback_speed;
|
||||
|
@ -20,7 +20,6 @@
|
||||
#include <algorithm>
|
||||
#include <numeric>
|
||||
#include <string>
|
||||
#include <unordered_map>
|
||||
#include <utility>
|
||||
#include <vector>
|
||||
|
||||
|
@ -4,18 +4,12 @@
|
||||
#include "engine/api/trip_parameters.hpp"
|
||||
#include "engine/trip/trip_brute_force.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/json_container.hpp"
|
||||
|
||||
#include <boost/assert.hpp>
|
||||
|
||||
#include <algorithm>
|
||||
#include <cstdlib>
|
||||
#include <iterator>
|
||||
#include <limits>
|
||||
#include <memory>
|
||||
#include <string>
|
||||
#include <utility>
|
||||
#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
|
||||
// so on) and return the result
|
||||
InternalRouteResult TripPlugin::ComputeRoute(const RoutingAlgorithmsInterface &algorithms,
|
||||
const std::vector<PhantomNode> &snapped_phantoms,
|
||||
const std::vector<NodeID> &trip,
|
||||
const bool roundtrip) const
|
||||
InternalRouteResult
|
||||
TripPlugin::ComputeRoute(const RoutingAlgorithmsInterface &algorithms,
|
||||
const std::vector<PhantomNodeCandidates> &waypoint_candidates,
|
||||
const std::vector<NodeID> &trip,
|
||||
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
|
||||
if (roundtrip)
|
||||
{
|
||||
viapoint = PhantomNodes{snapped_phantoms[trip.back()], snapped_phantoms[trip.front()]};
|
||||
min_route.segment_end_coordinates.emplace_back(viapoint);
|
||||
trip_candidates.push_back(waypoint_candidates[trip.front()]);
|
||||
// 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
|
||||
{
|
||||
// trip comes out to be something like 0 1 4 3 2, so the sizes don't match
|
||||
BOOST_ASSERT(min_route.segment_end_coordinates.size() == trip.size() - 1);
|
||||
// trip comes out to be something like 0 1 4 3 2
|
||||
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");
|
||||
return min_route;
|
||||
}
|
||||
@ -226,7 +213,7 @@ Status TripPlugin::HandleRequest(const RoutingAlgorithmsInterface &algorithms,
|
||||
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);
|
||||
|
||||
|
@ -5,12 +5,10 @@
|
||||
|
||||
#include "util/for_each_pair.hpp"
|
||||
#include "util/integer_range.hpp"
|
||||
#include "util/json_container.hpp"
|
||||
|
||||
#include <cstdlib>
|
||||
|
||||
#include <algorithm>
|
||||
#include <memory>
|
||||
#include <string>
|
||||
#include <vector>
|
||||
|
||||
@ -95,19 +93,10 @@ Status ViaRoutePlugin::HandleRequest(const RoutingAlgorithmsInterface &algorithm
|
||||
}
|
||||
BOOST_ASSERT(phantom_node_pairs.size() == route_parameters.coordinates.size());
|
||||
|
||||
auto snapped_phantoms = SnapPhantomNodes(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);
|
||||
auto snapped_phantoms = SnapPhantomNodes(std::move(phantom_node_pairs));
|
||||
|
||||
api::RouteAPI route_api{facade, route_parameters};
|
||||
|
||||
InternalManyRoutesResult routes;
|
||||
|
||||
// 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.
|
||||
const auto wants_alternatives =
|
||||
@ -115,20 +104,23 @@ Status ViaRoutePlugin::HandleRequest(const RoutingAlgorithmsInterface &algorithm
|
||||
(route_parameters.alternatives || route_parameters.number_of_alternatives > 0);
|
||||
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
|
||||
// See the implementation notes and high-level outline.
|
||||
// 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
|
||||
{
|
||||
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.
|
||||
@ -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
|
||||
{
|
||||
auto first_component_id = snapped_phantoms.front().component.id;
|
||||
auto not_in_same_component = std::any_of(snapped_phantoms.begin(),
|
||||
snapped_phantoms.end(),
|
||||
[first_component_id](const PhantomNode &node) {
|
||||
return node.component.id != first_component_id;
|
||||
});
|
||||
const auto all_in_same_component =
|
||||
[](const std::vector<PhantomNodeCandidates> &waypoint_candidates) {
|
||||
return std::any_of(waypoint_candidates.front().begin(),
|
||||
waypoint_candidates.front().end(),
|
||||
// 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);
|
||||
}
|
||||
|
@ -190,8 +190,8 @@ void computeWeightAndSharingOfViaPath(SearchEngineData<Algorithm> &engine_workin
|
||||
s_v_middle,
|
||||
upper_bound_s_v_path_weight,
|
||||
min_edge_offset,
|
||||
DO_NOT_FORCE_LOOPS,
|
||||
DO_NOT_FORCE_LOOPS);
|
||||
{},
|
||||
{});
|
||||
}
|
||||
// compute path <v,..,t> by reusing backward search from node t
|
||||
NodeID v_t_middle = SPECIAL_NODEID;
|
||||
@ -205,8 +205,8 @@ void computeWeightAndSharingOfViaPath(SearchEngineData<Algorithm> &engine_workin
|
||||
v_t_middle,
|
||||
upper_bound_of_v_t_path_weight,
|
||||
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;
|
||||
|
||||
@ -351,8 +351,8 @@ bool viaNodeCandidatePassesTTest(SearchEngineData<Algorithm> &engine_working_dat
|
||||
*s_v_middle,
|
||||
upper_bound_s_v_path_weight,
|
||||
min_edge_offset,
|
||||
DO_NOT_FORCE_LOOPS,
|
||||
DO_NOT_FORCE_LOOPS);
|
||||
{},
|
||||
{});
|
||||
}
|
||||
|
||||
if (INVALID_EDGE_WEIGHT == upper_bound_s_v_path_weight)
|
||||
@ -372,8 +372,8 @@ bool viaNodeCandidatePassesTTest(SearchEngineData<Algorithm> &engine_working_dat
|
||||
*v_t_middle,
|
||||
upper_bound_of_v_t_path_weight,
|
||||
min_edge_offset,
|
||||
DO_NOT_FORCE_LOOPS,
|
||||
DO_NOT_FORCE_LOOPS);
|
||||
{},
|
||||
{});
|
||||
}
|
||||
|
||||
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())
|
||||
{
|
||||
routingStep<FORWARD_DIRECTION>(facade,
|
||||
forward_heap3,
|
||||
reverse_heap3,
|
||||
middle,
|
||||
upper_bound,
|
||||
min_edge_offset,
|
||||
DO_NOT_FORCE_LOOPS,
|
||||
DO_NOT_FORCE_LOOPS);
|
||||
routingStep<FORWARD_DIRECTION>(
|
||||
facade, forward_heap3, reverse_heap3, middle, upper_bound, min_edge_offset, {}, {});
|
||||
}
|
||||
if (!reverse_heap3.Empty())
|
||||
{
|
||||
routingStep<REVERSE_DIRECTION>(facade,
|
||||
reverse_heap3,
|
||||
forward_heap3,
|
||||
middle,
|
||||
upper_bound,
|
||||
min_edge_offset,
|
||||
DO_NOT_FORCE_LOOPS,
|
||||
DO_NOT_FORCE_LOOPS);
|
||||
routingStep<REVERSE_DIRECTION>(
|
||||
facade, reverse_heap3, forward_heap3, middle, upper_bound, min_edge_offset, {}, {});
|
||||
}
|
||||
}
|
||||
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,
|
||||
const DataFacade<Algorithm> &facade,
|
||||
const PhantomNodes &phantom_node_pair,
|
||||
const PhantomEndpointCandidates &endpoint_candidates,
|
||||
unsigned /*number_of_alternatives*/)
|
||||
{
|
||||
InternalRouteResult primary_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> via_node_candidate_list;
|
||||
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;
|
||||
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
|
||||
while (0 < (forward_heap1.Size() + reverse_heap1.Size()))
|
||||
@ -790,7 +773,7 @@ InternalManyRoutesResult alternativePathSearch(SearchEngineData<Algorithm> &engi
|
||||
&v_t_middle,
|
||||
min_edge_offset))
|
||||
{
|
||||
// select first admissable
|
||||
// select first admissible
|
||||
selected_via_node = candidate.node;
|
||||
break;
|
||||
}
|
||||
@ -799,20 +782,23 @@ InternalManyRoutesResult alternativePathSearch(SearchEngineData<Algorithm> &engi
|
||||
// Unpack shortest path and alternative, if they exist
|
||||
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());
|
||||
primary_route.unpacked_path_segments.resize(1);
|
||||
primary_route.source_traversed_in_reverse.push_back(
|
||||
(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((
|
||||
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,
|
||||
// -- packed input
|
||||
packed_shortest_path.begin(),
|
||||
packed_shortest_path.end(),
|
||||
// -- start of route
|
||||
phantom_node_pair,
|
||||
phantom_endpoints,
|
||||
// -- unpacked output
|
||||
primary_route.unpacked_path_segments.front());
|
||||
primary_route.shortest_path_weight = upper_bound_to_shortest_path_weight;
|
||||
@ -830,19 +816,23 @@ InternalManyRoutesResult alternativePathSearch(SearchEngineData<Algorithm> &engi
|
||||
v_t_middle,
|
||||
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.source_traversed_in_reverse.push_back(
|
||||
(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(
|
||||
(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
|
||||
unpackPath(facade,
|
||||
packed_alternate_path.begin(),
|
||||
packed_alternate_path.end(),
|
||||
phantom_node_pair,
|
||||
phantom_endpoints,
|
||||
secondary_route.unpacked_path_segments.front());
|
||||
|
||||
secondary_route.shortest_path_weight = weight_of_via_path;
|
||||
|
@ -133,12 +133,13 @@ double getLongerByFactorBasedOnDuration(const EdgeWeight duration)
|
||||
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;
|
||||
|
||||
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
|
||||
if (distance < 10000.)
|
||||
@ -547,7 +548,7 @@ void unpackPackedPaths(InputIt first,
|
||||
OutIt out,
|
||||
SearchEngineData<Algorithm> &search_engine_data,
|
||||
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<OutIt, std::output_iterator_tag>();
|
||||
@ -600,7 +601,7 @@ void unpackPackedPaths(InputIt first,
|
||||
}
|
||||
else
|
||||
{ // 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);
|
||||
BOOST_ASSERT(parent_cell_id == partition.GetCell(level, target));
|
||||
|
||||
@ -624,8 +625,8 @@ void unpackPackedPaths(InputIt first,
|
||||
facade,
|
||||
forward_heap,
|
||||
reverse_heap,
|
||||
DO_NOT_FORCE_LOOPS,
|
||||
DO_NOT_FORCE_LOOPS,
|
||||
{},
|
||||
{},
|
||||
INVALID_EDGE_WEIGHT,
|
||||
sublevel,
|
||||
parent_cell_id);
|
||||
@ -656,13 +657,13 @@ void unpackPackedPaths(InputIt first,
|
||||
inline std::vector<WeightedViaNode>
|
||||
makeCandidateVias(SearchEngineData<Algorithm> &search_engine_data,
|
||||
const Facade &facade,
|
||||
const PhantomNodes &phantom_node_pair,
|
||||
const PhantomEndpointCandidates &endpoint_candidates,
|
||||
const Parameters ¶meters)
|
||||
{
|
||||
Heap &forward_heap = *search_engine_data.forward_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())
|
||||
{
|
||||
return {};
|
||||
@ -712,9 +713,9 @@ makeCandidateVias(SearchEngineData<Algorithm> &search_engine_data,
|
||||
reverse_heap,
|
||||
overlap_via,
|
||||
overlap_weight,
|
||||
DO_NOT_FORCE_LOOPS,
|
||||
DO_NOT_FORCE_LOOPS,
|
||||
phantom_node_pair);
|
||||
{},
|
||||
{},
|
||||
endpoint_candidates);
|
||||
|
||||
if (!forward_heap.Empty())
|
||||
forward_heap_min = forward_heap.MinKey();
|
||||
@ -738,9 +739,9 @@ makeCandidateVias(SearchEngineData<Algorithm> &search_engine_data,
|
||||
forward_heap,
|
||||
overlap_via,
|
||||
overlap_weight,
|
||||
DO_NOT_FORCE_LOOPS,
|
||||
DO_NOT_FORCE_LOOPS,
|
||||
phantom_node_pair);
|
||||
{},
|
||||
{},
|
||||
endpoint_candidates);
|
||||
|
||||
if (!reverse_heap.Empty())
|
||||
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
|
||||
InternalManyRoutesResult alternativePathSearch(SearchEngineData<Algorithm> &search_engine_data,
|
||||
const Facade &facade,
|
||||
const PhantomNodes &phantom_node_pair,
|
||||
const PhantomEndpointCandidates &endpoint_candidates,
|
||||
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_to_unpack =
|
||||
@ -798,7 +799,7 @@ InternalManyRoutesResult alternativePathSearch(SearchEngineData<Algorithm> &sear
|
||||
|
||||
// Do forward and backward search, save search space overlap as via candidates.
|
||||
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; };
|
||||
auto shortest_path_via_it =
|
||||
@ -813,8 +814,6 @@ InternalManyRoutesResult alternativePathSearch(SearchEngineData<Algorithm> &sear
|
||||
if (!has_shortest_path)
|
||||
{
|
||||
InternalRouteResult invalid;
|
||||
invalid.shortest_path_weight = INVALID_EDGE_WEIGHT;
|
||||
invalid.segment_end_coordinates = {phantom_node_pair};
|
||||
return invalid;
|
||||
}
|
||||
|
||||
@ -900,7 +899,7 @@ InternalManyRoutesResult alternativePathSearch(SearchEngineData<Algorithm> &sear
|
||||
std::back_inserter(unpacked_paths),
|
||||
search_engine_data,
|
||||
facade,
|
||||
phantom_node_pair);
|
||||
endpoint_candidates);
|
||||
|
||||
//
|
||||
// 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);
|
||||
|
||||
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,
|
||||
|
@ -19,7 +19,7 @@ namespace routing_algorithms
|
||||
template <>
|
||||
InternalRouteResult directShortestPathSearch(SearchEngineData<ch::Algorithm> &engine_working_data,
|
||||
const DataFacade<ch::Algorithm> &facade,
|
||||
const PhantomNodes &phantom_nodes)
|
||||
const PhantomEndpointCandidates &endpoint_candidates)
|
||||
{
|
||||
engine_working_data.InitializeOrClearFirstThreadLocalStorage(facade.GetNumberOfNodes());
|
||||
auto &forward_heap = *engine_working_data.forward_heap_1;
|
||||
@ -29,7 +29,7 @@ InternalRouteResult directShortestPathSearch(SearchEngineData<ch::Algorithm> &en
|
||||
|
||||
EdgeWeight weight = INVALID_EDGE_WEIGHT;
|
||||
std::vector<NodeID> packed_leg;
|
||||
insertNodesInHeaps(forward_heap, reverse_heap, phantom_nodes);
|
||||
insertNodesInHeaps(forward_heap, reverse_heap, endpoint_candidates);
|
||||
|
||||
search(engine_working_data,
|
||||
facade,
|
||||
@ -37,9 +37,9 @@ InternalRouteResult directShortestPathSearch(SearchEngineData<ch::Algorithm> &en
|
||||
reverse_heap,
|
||||
weight,
|
||||
packed_leg,
|
||||
DO_NOT_FORCE_LOOPS,
|
||||
DO_NOT_FORCE_LOOPS,
|
||||
phantom_nodes);
|
||||
{},
|
||||
{},
|
||||
endpoint_candidates);
|
||||
|
||||
std::vector<NodeID> unpacked_nodes;
|
||||
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 <>
|
||||
InternalRouteResult directShortestPathSearch(SearchEngineData<mld::Algorithm> &engine_working_data,
|
||||
const DataFacade<mld::Algorithm> &facade,
|
||||
const PhantomNodes &phantom_nodes)
|
||||
const PhantomEndpointCandidates &endpoint_candidates)
|
||||
{
|
||||
engine_working_data.InitializeOrClearFirstThreadLocalStorage(facade.GetNumberOfNodes(),
|
||||
facade.GetMaxBorderNodeID() + 1);
|
||||
auto &forward_heap = *engine_working_data.forward_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
|
||||
// auto [weight, source_node, target_node, unpacked_edges] = ...
|
||||
@ -83,12 +83,12 @@ InternalRouteResult directShortestPathSearch(SearchEngineData<mld::Algorithm> &e
|
||||
facade,
|
||||
forward_heap,
|
||||
reverse_heap,
|
||||
DO_NOT_FORCE_LOOPS,
|
||||
DO_NOT_FORCE_LOOPS,
|
||||
{},
|
||||
{},
|
||||
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
|
||||
|
@ -49,7 +49,7 @@ void relaxOutgoingEdges(
|
||||
const DataFacade<Algorithm> &facade,
|
||||
const typename SearchEngineData<Algorithm>::ManyToManyQueryHeap::HeapNode &heapNode,
|
||||
typename SearchEngineData<Algorithm>::ManyToManyQueryHeap &query_heap,
|
||||
const PhantomNode &)
|
||||
const PhantomNodeCandidates &)
|
||||
{
|
||||
if (stallAtNode<DIRECTION>(facade, heapNode, query_heap))
|
||||
{
|
||||
@ -99,7 +99,7 @@ void forwardRoutingStep(const DataFacade<Algorithm> &facade,
|
||||
std::vector<EdgeDuration> &durations_table,
|
||||
std::vector<EdgeDistance> &distances_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
|
||||
// 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,
|
||||
const unsigned column_index,
|
||||
typename SearchEngineData<Algorithm>::ManyToManyQueryHeap &query_heap,
|
||||
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
|
||||
// toHeapNode is the same
|
||||
@ -172,7 +172,7 @@ void backwardRoutingStep(const DataFacade<Algorithm> &facade,
|
||||
heapNode.data.duration,
|
||||
heapNode.data.distance);
|
||||
|
||||
relaxOutgoingEdges<REVERSE_DIRECTION>(facade, heapNode, query_heap, phantom_node);
|
||||
relaxOutgoingEdges<REVERSE_DIRECTION>(facade, heapNode, query_heap, candidates);
|
||||
}
|
||||
|
||||
} // namespace ch
|
||||
@ -181,7 +181,7 @@ template <>
|
||||
std::pair<std::vector<EdgeDuration>, std::vector<EdgeDistance>>
|
||||
manyToManySearch(SearchEngineData<ch::Algorithm> &engine_working_data,
|
||||
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> &target_indices,
|
||||
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)
|
||||
{
|
||||
const auto index = target_indices[column_index];
|
||||
const auto &phantom = phantom_nodes[index];
|
||||
const auto &target_candidates = candidates_list[index];
|
||||
|
||||
engine_working_data.InitializeOrClearManyToManyThreadLocalStorage(
|
||||
facade.GetNumberOfNodes());
|
||||
auto &query_heap = *(engine_working_data.many_to_many_heap);
|
||||
insertTargetInHeap(query_heap, phantom);
|
||||
insertTargetInHeap(query_heap, target_candidates);
|
||||
|
||||
// Explore search space
|
||||
while (!query_heap.Empty())
|
||||
{
|
||||
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)
|
||||
{
|
||||
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
|
||||
engine_working_data.InitializeOrClearManyToManyThreadLocalStorage(
|
||||
facade.GetNumberOfNodes());
|
||||
auto &query_heap = *(engine_working_data.many_to_many_heap);
|
||||
insertSourceInHeap(query_heap, source_phantom);
|
||||
insertSourceInHeap(query_heap, source_candidates);
|
||||
|
||||
// Explore search space
|
||||
while (!query_heap.Empty())
|
||||
@ -244,7 +244,7 @@ manyToManySearch(SearchEngineData<ch::Algorithm> &engine_working_data,
|
||||
durations_table,
|
||||
distances_table,
|
||||
middle_nodes_table,
|
||||
source_phantom);
|
||||
source_candidates);
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -25,7 +25,7 @@ using PackedPath = std::vector<PackedEdge>;
|
||||
template <typename MultiLevelPartition>
|
||||
inline LevelID getNodeQueryLevel(const MultiLevelPartition &partition,
|
||||
const NodeID node,
|
||||
const PhantomNode &phantom_node,
|
||||
const PhantomNodeCandidates &phantom_node,
|
||||
const LevelID maximal_level)
|
||||
{
|
||||
const auto node_level = getNodeQueryLevel(partition, node, phantom_node);
|
||||
@ -96,7 +96,7 @@ void relaxOutgoingEdges(
|
||||
const DataFacade<mld::Algorithm> &facade,
|
||||
const typename SearchEngineData<mld::Algorithm>::ManyToManyQueryHeap::HeapNode &heapNode,
|
||||
typename SearchEngineData<mld::Algorithm>::ManyToManyQueryHeap &query_heap,
|
||||
Args... args)
|
||||
const Args &... args)
|
||||
{
|
||||
BOOST_ASSERT(!facade.ExcludeNode(heapNode.node));
|
||||
|
||||
@ -214,59 +214,63 @@ template <bool DIRECTION>
|
||||
std::pair<std::vector<EdgeDuration>, std::vector<EdgeDistance>>
|
||||
oneToManySearch(SearchEngineData<Algorithm> &engine_working_data,
|
||||
const DataFacade<Algorithm> &facade,
|
||||
const std::vector<PhantomNode> &phantom_nodes,
|
||||
std::size_t phantom_index,
|
||||
const std::vector<std::size_t> &phantom_indices,
|
||||
const std::vector<PhantomNodeCandidates> &candidates_list,
|
||||
std::size_t source_index,
|
||||
const std::vector<std::size_t> &target_indices,
|
||||
const bool calculate_distance)
|
||||
{
|
||||
std::vector<EdgeWeight> weights_table(phantom_indices.size(), INVALID_EDGE_WEIGHT);
|
||||
std::vector<EdgeDuration> durations_table(phantom_indices.size(), MAXIMAL_EDGE_DURATION);
|
||||
std::vector<EdgeDistance> distances_table(calculate_distance ? phantom_indices.size() : 0,
|
||||
std::vector<EdgeWeight> weights_table(target_indices.size(), INVALID_EDGE_WEIGHT);
|
||||
std::vector<EdgeDuration> durations_table(target_indices.size(), MAXIMAL_EDGE_DURATION);
|
||||
std::vector<EdgeDistance> distances_table(calculate_distance ? target_indices.size() : 0,
|
||||
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
|
||||
std::unordered_multimap<NodeID, std::tuple<std::size_t, EdgeWeight, EdgeDuration, EdgeDistance>>
|
||||
target_nodes_index;
|
||||
target_nodes_index.reserve(phantom_indices.size());
|
||||
for (std::size_t index = 0; index < phantom_indices.size(); ++index)
|
||||
target_nodes_index.reserve(target_indices.size());
|
||||
for (std::size_t index = 0; index < target_indices.size(); ++index)
|
||||
{
|
||||
const auto &phantom_index = phantom_indices[index];
|
||||
const auto &phantom_node = phantom_nodes[phantom_index];
|
||||
const auto &target_candidates = candidates_list[target_indices[index]];
|
||||
|
||||
if (DIRECTION == FORWARD_DIRECTION)
|
||||
for (const auto &phantom_node : target_candidates)
|
||||
{
|
||||
if (phantom_node.IsValidForwardTarget())
|
||||
target_nodes_index.insert(
|
||||
{phantom_node.forward_segment_id.id,
|
||||
std::make_tuple(index,
|
||||
phantom_node.GetForwardWeightPlusOffset(),
|
||||
phantom_node.GetForwardDuration(),
|
||||
phantom_node.GetForwardDistance())});
|
||||
if (phantom_node.IsValidReverseTarget())
|
||||
target_nodes_index.insert(
|
||||
{phantom_node.reverse_segment_id.id,
|
||||
std::make_tuple(index,
|
||||
phantom_node.GetReverseWeightPlusOffset(),
|
||||
phantom_node.GetReverseDuration(),
|
||||
phantom_node.GetReverseDistance())});
|
||||
}
|
||||
else if (DIRECTION == REVERSE_DIRECTION)
|
||||
{
|
||||
if (phantom_node.IsValidForwardSource())
|
||||
target_nodes_index.insert(
|
||||
{phantom_node.forward_segment_id.id,
|
||||
std::make_tuple(index,
|
||||
-phantom_node.GetForwardWeightPlusOffset(),
|
||||
-phantom_node.GetForwardDuration(),
|
||||
-phantom_node.GetForwardDistance())});
|
||||
if (phantom_node.IsValidReverseSource())
|
||||
target_nodes_index.insert(
|
||||
{phantom_node.reverse_segment_id.id,
|
||||
std::make_tuple(index,
|
||||
-phantom_node.GetReverseWeightPlusOffset(),
|
||||
-phantom_node.GetReverseDuration(),
|
||||
-phantom_node.GetReverseDistance())});
|
||||
if (DIRECTION == FORWARD_DIRECTION)
|
||||
{
|
||||
if (phantom_node.IsValidForwardTarget())
|
||||
target_nodes_index.insert(
|
||||
{phantom_node.forward_segment_id.id,
|
||||
std::make_tuple(index,
|
||||
phantom_node.GetForwardWeightPlusOffset(),
|
||||
phantom_node.GetForwardDuration(),
|
||||
phantom_node.GetForwardDistance())});
|
||||
|
||||
if (phantom_node.IsValidReverseTarget())
|
||||
target_nodes_index.insert(
|
||||
{phantom_node.reverse_segment_id.id,
|
||||
std::make_tuple(index,
|
||||
phantom_node.GetReverseWeightPlusOffset(),
|
||||
phantom_node.GetReverseDuration(),
|
||||
phantom_node.GetReverseDistance())});
|
||||
}
|
||||
else if (DIRECTION == REVERSE_DIRECTION)
|
||||
{
|
||||
if (phantom_node.IsValidForwardSource())
|
||||
target_nodes_index.insert(
|
||||
{phantom_node.forward_segment_id.id,
|
||||
std::make_tuple(index,
|
||||
-phantom_node.GetForwardWeightPlusOffset(),
|
||||
-phantom_node.GetForwardDuration(),
|
||||
-phantom_node.GetForwardDistance())});
|
||||
|
||||
if (phantom_node.IsValidReverseSource())
|
||||
target_nodes_index.insert(
|
||||
{phantom_node.reverse_segment_id.id,
|
||||
std::make_tuple(index,
|
||||
-phantom_node.GetReverseWeightPlusOffset(),
|
||||
-phantom_node.GetReverseDuration(),
|
||||
-phantom_node.GetReverseDistance())});
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@ -337,42 +341,45 @@ oneToManySearch(SearchEngineData<Algorithm> &engine_working_data,
|
||||
};
|
||||
|
||||
{ // Place source (destination) adjacent nodes into the heap
|
||||
const auto &phantom_node = phantom_nodes[phantom_index];
|
||||
const auto &source_candidates = candidates_list[source_index];
|
||||
|
||||
if (DIRECTION == FORWARD_DIRECTION)
|
||||
for (const auto &phantom_node : source_candidates)
|
||||
{
|
||||
if (phantom_node.IsValidForwardSource())
|
||||
if (DIRECTION == FORWARD_DIRECTION)
|
||||
{
|
||||
insert_node(phantom_node.forward_segment_id.id,
|
||||
-phantom_node.GetForwardWeightPlusOffset(),
|
||||
-phantom_node.GetForwardDuration(),
|
||||
-phantom_node.GetForwardDistance());
|
||||
}
|
||||
if (phantom_node.IsValidForwardSource())
|
||||
{
|
||||
insert_node(phantom_node.forward_segment_id.id,
|
||||
-phantom_node.GetForwardWeightPlusOffset(),
|
||||
-phantom_node.GetForwardDuration(),
|
||||
-phantom_node.GetForwardDistance());
|
||||
}
|
||||
|
||||
if (phantom_node.IsValidReverseSource())
|
||||
{
|
||||
insert_node(phantom_node.reverse_segment_id.id,
|
||||
-phantom_node.GetReverseWeightPlusOffset(),
|
||||
-phantom_node.GetReverseDuration(),
|
||||
-phantom_node.GetReverseDistance());
|
||||
if (phantom_node.IsValidReverseSource())
|
||||
{
|
||||
insert_node(phantom_node.reverse_segment_id.id,
|
||||
-phantom_node.GetReverseWeightPlusOffset(),
|
||||
-phantom_node.GetReverseDuration(),
|
||||
-phantom_node.GetReverseDistance());
|
||||
}
|
||||
}
|
||||
}
|
||||
else if (DIRECTION == REVERSE_DIRECTION)
|
||||
{
|
||||
if (phantom_node.IsValidForwardTarget())
|
||||
else if (DIRECTION == REVERSE_DIRECTION)
|
||||
{
|
||||
insert_node(phantom_node.forward_segment_id.id,
|
||||
phantom_node.GetForwardWeightPlusOffset(),
|
||||
phantom_node.GetForwardDuration(),
|
||||
phantom_node.GetForwardDistance());
|
||||
}
|
||||
if (phantom_node.IsValidForwardTarget())
|
||||
{
|
||||
insert_node(phantom_node.forward_segment_id.id,
|
||||
phantom_node.GetForwardWeightPlusOffset(),
|
||||
phantom_node.GetForwardDuration(),
|
||||
phantom_node.GetForwardDistance());
|
||||
}
|
||||
|
||||
if (phantom_node.IsValidReverseTarget())
|
||||
{
|
||||
insert_node(phantom_node.reverse_segment_id.id,
|
||||
phantom_node.GetReverseWeightPlusOffset(),
|
||||
phantom_node.GetReverseDuration(),
|
||||
phantom_node.GetReverseDistance());
|
||||
if (phantom_node.IsValidReverseTarget())
|
||||
{
|
||||
insert_node(phantom_node.reverse_segment_id.id,
|
||||
phantom_node.GetReverseWeightPlusOffset(),
|
||||
phantom_node.GetReverseDuration(),
|
||||
phantom_node.GetReverseDistance());
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -389,7 +396,7 @@ oneToManySearch(SearchEngineData<Algorithm> &engine_working_data,
|
||||
|
||||
// Relax outgoing edges
|
||||
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));
|
||||
@ -409,7 +416,7 @@ void forwardRoutingStep(const DataFacade<Algorithm> &facade,
|
||||
std::vector<EdgeDuration> &durations_table,
|
||||
std::vector<EdgeDistance> &distances_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
|
||||
// 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>
|
||||
@ -463,7 +470,7 @@ void backwardRoutingStep(const DataFacade<Algorithm> &facade,
|
||||
const unsigned column_idx,
|
||||
typename SearchEngineData<Algorithm>::ManyToManyQueryHeap &query_heap,
|
||||
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
|
||||
// the same
|
||||
@ -481,7 +488,7 @@ void backwardRoutingStep(const DataFacade<Algorithm> &facade,
|
||||
const auto &partition = facade.GetMultiLevelPartition();
|
||||
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>
|
||||
@ -524,7 +531,7 @@ template <bool DIRECTION>
|
||||
std::pair<std::vector<EdgeDuration>, std::vector<EdgeDistance>>
|
||||
manyToManySearch(SearchEngineData<Algorithm> &engine_working_data,
|
||||
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> &target_indices,
|
||||
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)
|
||||
{
|
||||
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(
|
||||
facade.GetNumberOfNodes(), facade.GetMaxBorderNodeID() + 1);
|
||||
auto &query_heap = *(engine_working_data.many_to_many_heap);
|
||||
|
||||
if (DIRECTION == FORWARD_DIRECTION)
|
||||
insertTargetInHeap(query_heap, target_phantom);
|
||||
insertTargetInHeap(query_heap, target_candidates);
|
||||
else
|
||||
insertSourceInHeap(query_heap, target_phantom);
|
||||
insertSourceInHeap(query_heap, target_candidates);
|
||||
|
||||
// explore search space
|
||||
while (!query_heap.Empty())
|
||||
{
|
||||
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)
|
||||
{
|
||||
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
|
||||
engine_working_data.InitializeOrClearManyToManyThreadLocalStorage(
|
||||
@ -580,9 +587,9 @@ manyToManySearch(SearchEngineData<Algorithm> &engine_working_data,
|
||||
auto &query_heap = *(engine_working_data.many_to_many_heap);
|
||||
|
||||
if (DIRECTION == FORWARD_DIRECTION)
|
||||
insertSourceInHeap(query_heap, source_phantom);
|
||||
insertSourceInHeap(query_heap, source_candidates);
|
||||
else
|
||||
insertTargetInHeap(query_heap, source_phantom);
|
||||
insertTargetInHeap(query_heap, source_candidates);
|
||||
|
||||
// Explore search space
|
||||
while (!query_heap.Empty())
|
||||
@ -597,7 +604,7 @@ manyToManySearch(SearchEngineData<Algorithm> &engine_working_data,
|
||||
durations_table,
|
||||
distances_table,
|
||||
middle_nodes_table,
|
||||
source_phantom);
|
||||
source_candidates);
|
||||
}
|
||||
}
|
||||
|
||||
@ -622,7 +629,7 @@ template <>
|
||||
std::pair<std::vector<EdgeDuration>, std::vector<EdgeDistance>>
|
||||
manyToManySearch(SearchEngineData<mld::Algorithm> &engine_working_data,
|
||||
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> &target_indices,
|
||||
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
|
||||
return mld::oneToManySearch<FORWARD_DIRECTION>(engine_working_data,
|
||||
facade,
|
||||
phantom_nodes,
|
||||
candidates_list,
|
||||
source_indices.front(),
|
||||
target_indices,
|
||||
calculate_distance);
|
||||
@ -641,7 +648,7 @@ manyToManySearch(SearchEngineData<mld::Algorithm> &engine_working_data,
|
||||
{
|
||||
return mld::oneToManySearch<REVERSE_DIRECTION>(engine_working_data,
|
||||
facade,
|
||||
phantom_nodes,
|
||||
candidates_list,
|
||||
target_indices.front(),
|
||||
source_indices,
|
||||
calculate_distance);
|
||||
@ -651,7 +658,7 @@ manyToManySearch(SearchEngineData<mld::Algorithm> &engine_working_data,
|
||||
{
|
||||
return mld::manyToManySearch<REVERSE_DIRECTION>(engine_working_data,
|
||||
facade,
|
||||
phantom_nodes,
|
||||
candidates_list,
|
||||
target_indices,
|
||||
source_indices,
|
||||
calculate_distance);
|
||||
@ -659,7 +666,7 @@ manyToManySearch(SearchEngineData<mld::Algorithm> &engine_working_data,
|
||||
|
||||
return mld::manyToManySearch<FORWARD_DIRECTION>(engine_working_data,
|
||||
facade,
|
||||
phantom_nodes,
|
||||
candidates_list,
|
||||
source_indices,
|
||||
target_indices,
|
||||
calculate_distance);
|
||||
|
@ -7,30 +7,104 @@ namespace engine
|
||||
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() &&
|
||||
source_phantom.forward_segment_id.id == target_phantom.forward_segment_id.id &&
|
||||
source_phantom.GetForwardWeightPlusOffset() >
|
||||
target_phantom.GetForwardWeightPlusOffset();
|
||||
return source.IsValidForwardSource() && target.IsValidForwardTarget() &&
|
||||
source.forward_segment_id.id == target.forward_segment_id.id &&
|
||||
source.GetForwardWeightPlusOffset() > target.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() &&
|
||||
source_phantom.reverse_segment_id.id == target_phantom.reverse_segment_id.id &&
|
||||
source_phantom.GetReverseWeightPlusOffset() >
|
||||
target_phantom.GetReverseWeightPlusOffset();
|
||||
return source.IsValidReverseSource() && target.IsValidReverseTarget() &&
|
||||
source.reverse_segment_id.id == target.reverse_segment_id.id &&
|
||||
source.GetReverseWeightPlusOffset() > target.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
|
||||
|
@ -95,9 +95,8 @@ void search(SearchEngineData<Algorithm> & /*engine_working_data*/,
|
||||
SearchEngineData<Algorithm>::QueryHeap &reverse_heap,
|
||||
EdgeWeight &weight,
|
||||
std::vector<NodeID> &packed_leg,
|
||||
const bool force_loop_forward,
|
||||
const bool force_loop_reverse,
|
||||
const PhantomNodes & /*phantom_nodes*/,
|
||||
const std::vector<NodeID> &force_loop_forward_nodes,
|
||||
const std::vector<NodeID> &force_loop_reverse_nodes,
|
||||
const EdgeWeight weight_upper_bound)
|
||||
{
|
||||
if (forward_heap.Empty() || reverse_heap.Empty())
|
||||
@ -126,8 +125,8 @@ void search(SearchEngineData<Algorithm> & /*engine_working_data*/,
|
||||
middle,
|
||||
weight,
|
||||
min_edge_offset,
|
||||
force_loop_forward,
|
||||
force_loop_reverse);
|
||||
force_loop_forward_nodes,
|
||||
force_loop_reverse_nodes);
|
||||
}
|
||||
if (!reverse_heap.Empty())
|
||||
{
|
||||
@ -137,8 +136,8 @@ void search(SearchEngineData<Algorithm> & /*engine_working_data*/,
|
||||
middle,
|
||||
weight,
|
||||
min_edge_offset,
|
||||
force_loop_reverse,
|
||||
force_loop_forward);
|
||||
force_loop_reverse_nodes,
|
||||
force_loop_forward_nodes);
|
||||
}
|
||||
}
|
||||
|
||||
@ -179,7 +178,8 @@ double getNetworkDistance(SearchEngineData<Algorithm> &engine_working_data,
|
||||
forward_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;
|
||||
std::vector<NodeID> packed_path;
|
||||
@ -189,9 +189,9 @@ double getNetworkDistance(SearchEngineData<Algorithm> &engine_working_data,
|
||||
reverse_heap,
|
||||
weight,
|
||||
packed_path,
|
||||
DO_NOT_FORCE_LOOPS,
|
||||
DO_NOT_FORCE_LOOPS,
|
||||
{source_phantom, target_phantom},
|
||||
{},
|
||||
{},
|
||||
endpoints,
|
||||
weight_upper_bound);
|
||||
|
||||
if (weight == INVALID_EDGE_WEIGHT)
|
||||
|
@ -12,13 +12,13 @@ namespace routing_algorithms
|
||||
template InternalRouteResult
|
||||
shortestPathSearch(SearchEngineData<ch::Algorithm> &engine_working_data,
|
||||
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);
|
||||
|
||||
template InternalRouteResult
|
||||
shortestPathSearch(SearchEngineData<mld::Algorithm> &engine_working_data,
|
||||
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);
|
||||
|
||||
} // namespace routing_algorithms
|
||||
|
@ -44,16 +44,16 @@ BOOST_AUTO_TEST_CASE(hint_encoding_decoding_roundtrip)
|
||||
const PhantomNode phantom;
|
||||
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), '/'));
|
||||
|
||||
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)
|
||||
@ -65,12 +65,12 @@ BOOST_AUTO_TEST_CASE(hint_encoding_decoding_roundtrip_bytewise)
|
||||
const PhantomNode phantom;
|
||||
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),
|
||||
reinterpret_cast<const unsigned char *>(&hint) + sizeof(Hint),
|
||||
BOOST_CHECK(std::equal(reinterpret_cast<const unsigned char *>(&seg_hint),
|
||||
reinterpret_cast<const unsigned char *>(&seg_hint) + sizeof(Hint),
|
||||
reinterpret_cast<const unsigned char *>(&decoded)));
|
||||
}
|
||||
|
||||
|
@ -23,7 +23,7 @@ BOOST_AUTO_TEST_CASE(unchanged_collapse_route_result)
|
||||
PathData kathy{0, 1, 1, 2, 3, 4, 1, boost::none};
|
||||
InternalRouteResult one_leg_result;
|
||||
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.target_traversed_in_reverse = {true};
|
||||
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};
|
||||
InternalRouteResult two_leg_result;
|
||||
two_leg_result.unpacked_path_segments = {{pathy, kathy}, {kathy, cathy}};
|
||||
two_leg_result.segment_end_coordinates = {PhantomNodes{node_1, node_2},
|
||||
PhantomNodes{node_2, node_3}};
|
||||
two_leg_result.leg_endpoints = {PhantomEndpoints{node_1, node_2},
|
||||
PhantomEndpoints{node_2, node_3}};
|
||||
two_leg_result.source_traversed_in_reverse = {true, false};
|
||||
two_leg_result.target_traversed_in_reverse = {true, false};
|
||||
two_leg_result.shortest_path_weight = 80;
|
||||
|
||||
auto collapsed = CollapseInternalRouteResult(two_leg_result, {true, false, true, true});
|
||||
BOOST_CHECK_EQUAL(collapsed.unpacked_path_segments.size(), 1);
|
||||
BOOST_CHECK_EQUAL(collapsed.segment_end_coordinates.size(), 1);
|
||||
BOOST_CHECK_EQUAL(collapsed.segment_end_coordinates[0].target_phantom.forward_segment_id.id,
|
||||
12);
|
||||
BOOST_CHECK_EQUAL(collapsed.segment_end_coordinates[0].source_phantom.forward_segment_id.id, 1);
|
||||
BOOST_CHECK_EQUAL(collapsed.leg_endpoints.size(), 1);
|
||||
BOOST_CHECK_EQUAL(collapsed.leg_endpoints[0].target_phantom.forward_segment_id.id, 12);
|
||||
BOOST_CHECK_EQUAL(collapsed.leg_endpoints[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][0].turn_via_node, 2);
|
||||
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},
|
||||
std::vector<PathData>{kathy, qathy, cathy},
|
||||
std::vector<PathData>{cathy, mathy}};
|
||||
three_leg_result.segment_end_coordinates = {
|
||||
PhantomNodes{node_1, node_2}, PhantomNodes{node_2, node_3}, PhantomNodes{node_3, node_4}};
|
||||
three_leg_result.leg_endpoints = {PhantomEndpoints{node_1, node_2},
|
||||
PhantomEndpoints{node_2, node_3},
|
||||
PhantomEndpoints{node_3, node_4}};
|
||||
three_leg_result.source_traversed_in_reverse = {true, false, true},
|
||||
three_leg_result.target_traversed_in_reverse = {true, false, true},
|
||||
three_leg_result.shortest_path_weight = 140;
|
||||
|
||||
auto collapsed = CollapseInternalRouteResult(three_leg_result, {true, true, false, true});
|
||||
BOOST_CHECK_EQUAL(collapsed.unpacked_path_segments.size(), 2);
|
||||
BOOST_CHECK_EQUAL(collapsed.segment_end_coordinates.size(), 2);
|
||||
BOOST_CHECK_EQUAL(collapsed.segment_end_coordinates[0].source_phantom.forward_segment_id.id, 1);
|
||||
BOOST_CHECK_EQUAL(collapsed.segment_end_coordinates[0].target_phantom.forward_segment_id.id, 6);
|
||||
BOOST_CHECK_EQUAL(collapsed.segment_end_coordinates[1].source_phantom.forward_segment_id.id, 6);
|
||||
BOOST_CHECK_EQUAL(collapsed.segment_end_coordinates[1].target_phantom.forward_segment_id.id,
|
||||
18);
|
||||
BOOST_CHECK_EQUAL(collapsed.leg_endpoints.size(), 2);
|
||||
BOOST_CHECK_EQUAL(collapsed.leg_endpoints[0].source_phantom.forward_segment_id.id, 1);
|
||||
BOOST_CHECK_EQUAL(collapsed.leg_endpoints[0].target_phantom.forward_segment_id.id, 6);
|
||||
BOOST_CHECK_EQUAL(collapsed.leg_endpoints[1].source_phantom.forward_segment_id.id, 6);
|
||||
BOOST_CHECK_EQUAL(collapsed.leg_endpoints[1].target_phantom.forward_segment_id.id, 18);
|
||||
BOOST_CHECK_EQUAL(collapsed.unpacked_path_segments[0].size(), 2);
|
||||
BOOST_CHECK_EQUAL(collapsed.unpacked_path_segments[1].size(), 5);
|
||||
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};
|
||||
InternalRouteResult two_leg_result;
|
||||
two_leg_result.unpacked_path_segments = {{pathy, kathy}, {kathy, cathy}};
|
||||
two_leg_result.segment_end_coordinates = {PhantomNodes{node_1, node_2},
|
||||
PhantomNodes{node_2, node_3}};
|
||||
two_leg_result.leg_endpoints = {PhantomEndpoints{node_1, node_2},
|
||||
PhantomEndpoints{node_2, node_3}};
|
||||
two_leg_result.source_traversed_in_reverse = {true, false};
|
||||
two_leg_result.target_traversed_in_reverse = {true, false};
|
||||
two_leg_result.shortest_path_weight = 80;
|
||||
|
||||
auto collapsed = CollapseInternalRouteResult(two_leg_result, {true, true, true});
|
||||
BOOST_CHECK_EQUAL(collapsed.unpacked_path_segments.size(), 2);
|
||||
BOOST_CHECK_EQUAL(collapsed.segment_end_coordinates.size(), 2);
|
||||
BOOST_CHECK_EQUAL(collapsed.segment_end_coordinates[0].source_phantom.forward_segment_id.id, 1);
|
||||
BOOST_CHECK_EQUAL(collapsed.segment_end_coordinates[0].target_phantom.forward_segment_id.id, 6);
|
||||
BOOST_CHECK_EQUAL(collapsed.segment_end_coordinates[1].source_phantom.forward_segment_id.id, 6);
|
||||
BOOST_CHECK_EQUAL(collapsed.segment_end_coordinates[1].target_phantom.forward_segment_id.id,
|
||||
12);
|
||||
BOOST_CHECK_EQUAL(collapsed.leg_endpoints.size(), 2);
|
||||
BOOST_CHECK_EQUAL(collapsed.leg_endpoints[0].source_phantom.forward_segment_id.id, 1);
|
||||
BOOST_CHECK_EQUAL(collapsed.leg_endpoints[0].target_phantom.forward_segment_id.id, 6);
|
||||
BOOST_CHECK_EQUAL(collapsed.leg_endpoints[1].source_phantom.forward_segment_id.id, 6);
|
||||
BOOST_CHECK_EQUAL(collapsed.leg_endpoints[1].target_phantom.forward_segment_id.id, 12);
|
||||
BOOST_CHECK_EQUAL(collapsed.unpacked_path_segments[0].size(), 2);
|
||||
BOOST_CHECK_EQUAL(collapsed.unpacked_path_segments[1].size(), 2);
|
||||
BOOST_CHECK_EQUAL(collapsed.unpacked_path_segments[0][0].turn_via_node, 2);
|
||||
|
@ -224,101 +224,35 @@ class ContiguousInternalMemoryDataFacade<routing_algorithms::offline::Algorithm>
|
||||
return {};
|
||||
}
|
||||
|
||||
std::vector<PhantomNodeWithDistance>
|
||||
std::vector<engine::PhantomNodeWithDistance>
|
||||
NearestPhantomNodesInRange(const util::Coordinate /*input_coordinate*/,
|
||||
const float /*max_distance*/,
|
||||
const int /*bearing*/,
|
||||
const int /*bearing_range*/,
|
||||
const Approach /*approach*/,
|
||||
const double /*max_distance*/,
|
||||
const boost::optional<engine::Bearing> /*bearing*/,
|
||||
const engine::Approach /*approach*/,
|
||||
const bool /*use_all_edges*/) const override
|
||||
{
|
||||
return {};
|
||||
}
|
||||
};
|
||||
|
||||
std::vector<PhantomNodeWithDistance>
|
||||
NearestPhantomNodesInRange(const util::Coordinate /*input_coordinate*/,
|
||||
const float /*max_distance*/,
|
||||
const Approach /*approach*/,
|
||||
const bool /*use_all_edges*/) const override
|
||||
{
|
||||
return {};
|
||||
}
|
||||
|
||||
std::vector<PhantomNodeWithDistance>
|
||||
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 Approach /*approach*/) const override
|
||||
const size_t /*max_results*/,
|
||||
const boost::optional<double> /*max_distance*/,
|
||||
const boost::optional<engine::Bearing> /*bearing*/,
|
||||
const engine::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
|
||||
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
|
||||
{
|
||||
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
|
||||
{
|
||||
@ -394,15 +328,16 @@ namespace routing_algorithms
|
||||
namespace offline
|
||||
{
|
||||
|
||||
template <typename PhantomT>
|
||||
inline void search(SearchEngineData<Algorithm> &engine_working_data,
|
||||
const datafacade::ContiguousInternalMemoryDataFacade<Algorithm> &facade,
|
||||
typename SearchEngineData<Algorithm>::QueryHeap &forward_heap,
|
||||
typename SearchEngineData<Algorithm>::QueryHeap &reverse_heap,
|
||||
EdgeWeight &weight,
|
||||
std::vector<NodeID> &packed_leg,
|
||||
const bool force_loop_forward,
|
||||
const bool force_loop_reverse,
|
||||
const PhantomNodes &phantom_nodes,
|
||||
const std::vector<NodeID> &forward_loop_nodes,
|
||||
const std::vector<NodeID> &reverse_loop_nodes,
|
||||
const PhantomT &endpoints,
|
||||
const EdgeWeight weight_upper_bound = INVALID_EDGE_WEIGHT)
|
||||
{
|
||||
mld::search(engine_working_data,
|
||||
@ -411,9 +346,9 @@ inline void search(SearchEngineData<Algorithm> &engine_working_data,
|
||||
reverse_heap,
|
||||
weight,
|
||||
packed_leg,
|
||||
force_loop_forward,
|
||||
force_loop_reverse,
|
||||
phantom_nodes,
|
||||
forward_loop_nodes,
|
||||
reverse_loop_nodes,
|
||||
endpoints,
|
||||
weight_upper_bound);
|
||||
}
|
||||
|
||||
@ -421,10 +356,10 @@ template <typename RandomIter, typename FacadeT>
|
||||
void unpackPath(const FacadeT &facade,
|
||||
RandomIter packed_path_begin,
|
||||
RandomIter packed_path_end,
|
||||
const PhantomNodes &phantom_nodes,
|
||||
const PhantomEndpoints &endpoints,
|
||||
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
|
||||
@ -442,11 +377,12 @@ BOOST_AUTO_TEST_CASE(shortest_path)
|
||||
osrm::engine::SearchEngineData<Algorithm> heaps;
|
||||
osrm::engine::datafacade::ContiguousInternalMemoryDataFacade<Algorithm> facade;
|
||||
|
||||
std::vector<osrm::engine::PhantomNodes> phantom_nodes;
|
||||
phantom_nodes.push_back({osrm::engine::PhantomNode{}, osrm::engine::PhantomNode{}});
|
||||
std::vector<osrm::engine::PhantomNodeCandidates> waypoints;
|
||||
waypoints.push_back({osrm::engine::PhantomNode{}});
|
||||
waypoints.push_back({osrm::engine::PhantomNode{}});
|
||||
|
||||
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);
|
||||
}
|
||||
|
@ -110,99 +110,33 @@ class MockBaseDataFacade : public engine::datafacade::BaseDataFacade
|
||||
|
||||
std::vector<engine::PhantomNodeWithDistance>
|
||||
NearestPhantomNodesInRange(const util::Coordinate /*input_coordinate*/,
|
||||
const float /*max_distance*/,
|
||||
const int /*bearing*/,
|
||||
const int /*bearing_range*/,
|
||||
const double /*max_distance*/,
|
||||
const boost::optional<engine::Bearing> /*bearing*/,
|
||||
const engine::Approach /*approach*/,
|
||||
const bool /*use_all_edges*/) const override
|
||||
{
|
||||
return {};
|
||||
}
|
||||
|
||||
std::vector<engine::PhantomNodeWithDistance>
|
||||
NearestPhantomNodesInRange(const util::Coordinate /*input_coordinate*/,
|
||||
const float /*max_distance*/,
|
||||
const engine::Approach /*approach*/,
|
||||
const bool /*use_all_edges*/) const override
|
||||
{
|
||||
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 size_t /*max_results*/,
|
||||
const boost::optional<double> /*max_distance*/,
|
||||
const boost::optional<engine::Bearing> /*bearing*/,
|
||||
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
|
||||
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
|
||||
{
|
||||
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; }
|
||||
|
||||
|
@ -19,6 +19,20 @@
|
||||
#define CHECK_EQUAL_RANGE(R1, R2) \
|
||||
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)
|
||||
|
||||
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_AUTO_TEST_CASE(valid_route_hint)
|
||||
BOOST_AUTO_TEST_CASE(valid_route_segment_hint)
|
||||
{
|
||||
engine::PhantomNode reference_node;
|
||||
reference_node.input_location =
|
||||
util::Coordinate(util::FloatLongitude{7.432251}, util::FloatLatitude{43.745995});
|
||||
engine::Hint reference_hint{reference_node, 0x1337};
|
||||
auto encoded_hint = reference_hint.ToBase64();
|
||||
auto hint = engine::Hint::FromBase64(encoded_hint);
|
||||
BOOST_CHECK_EQUAL(hint.phantom.input_location, reference_hint.phantom.input_location);
|
||||
engine::SegmentHint reference_segment_hint{reference_node, 0x1337};
|
||||
auto encoded_hint = reference_segment_hint.ToBase64();
|
||||
auto seg_hint = engine::SegmentHint::FromBase64(encoded_hint);
|
||||
BOOST_CHECK_EQUAL(seg_hint.phantom.input_location,
|
||||
reference_segment_hint.phantom.input_location);
|
||||
}
|
||||
|
||||
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.approaches, result_1->approaches);
|
||||
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{};
|
||||
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.approaches, result_2->approaches);
|
||||
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);
|
||||
|
||||
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.approaches, result_3->approaches);
|
||||
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;
|
||||
phantom_1.input_location = coords_1[0];
|
||||
engine::PhantomNode phantom_2;
|
||||
phantom_2.input_location = coords_1[1];
|
||||
std::vector<boost::optional<engine::Hint>> hints_4 = {engine::Hint{phantom_1, 0x1337},
|
||||
engine::Hint{phantom_2, 0x1337}};
|
||||
std::vector<boost::optional<engine::Hint>> hints_4 = {
|
||||
engine::Hint{{engine::SegmentHint{phantom_1, 0x1337}}},
|
||||
engine::Hint{{engine::SegmentHint{phantom_2, 0x1337}}}};
|
||||
RouteParameters reference_4{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.approaches, result_4->approaches);
|
||||
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 = {
|
||||
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.approaches, result_5->approaches);
|
||||
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}},
|
||||
{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.approaches, result_6->approaches);
|
||||
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");
|
||||
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.approaches, result_7->approaches);
|
||||
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=;");
|
||||
RouteParameters reference_8{};
|
||||
@ -320,7 +336,10 @@ BOOST_AUTO_TEST_CASE(valid_route_urls)
|
||||
engine::PhantomNode phantom_4;
|
||||
phantom_4.input_location = coords_3[2];
|
||||
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,
|
||||
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.approaches, result_10->approaches);
|
||||
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
|
||||
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.approaches, result_18->approaches);
|
||||
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{};
|
||||
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.approaches, result_19->approaches);
|
||||
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{};
|
||||
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.approaches, result_20->approaches);
|
||||
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
|
||||
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.approaches, result_21->approaches);
|
||||
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);
|
||||
}
|
||||
|
||||
|
@ -200,8 +200,8 @@ void simple_verify_rtree(RTreeT &rtree,
|
||||
auto result_u = rtree.Nearest(pu, 1);
|
||||
auto result_v = rtree.Nearest(pv, 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_v.front().u == e.v || result_v.front().v == e.v);
|
||||
BOOST_CHECK(result_u.front().data.u == e.u || result_u.front().data.v == e.u);
|
||||
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);
|
||||
BOOST_CHECK(result_rtree.size() == 1);
|
||||
BOOST_CHECK(result_lsnn.size() == 1);
|
||||
auto rtree_u = result_rtree.back().u;
|
||||
auto rtree_v = result_rtree.back().v;
|
||||
auto rtree_u = result_rtree.back().data.u;
|
||||
auto rtree_v = result_rtree.back().data.v;
|
||||
auto lsnn_u = result_lsnn.back().u;
|
||||
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_ls.size() == 1);
|
||||
|
||||
BOOST_CHECK_EQUAL(result_ls.front().u, result_rtree.front().u);
|
||||
BOOST_CHECK_EQUAL(result_ls.front().v, result_rtree.front().v);
|
||||
BOOST_CHECK_EQUAL(result_ls.front().u, result_rtree.front().data.u);
|
||||
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
|
||||
@ -347,8 +347,8 @@ BOOST_AUTO_TEST_CASE(radius_regression_test)
|
||||
Coordinate input(FloatLongitude{5.2}, FloatLatitude{5.0});
|
||||
|
||||
{
|
||||
auto results = query.NearestPhantomNodesInRange(
|
||||
input, 0.01, osrm::engine::Approach::UNRESTRICTED, true);
|
||||
auto results = query.NearestPhantomNodes(
|
||||
input, osrm::engine::Approach::UNRESTRICTED, boost::none, 0.01, boost::none, true);
|
||||
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});
|
||||
|
||||
{
|
||||
auto results = query.NearestPhantomNodesInRange(
|
||||
input, 1000, osrm::engine::Approach::UNRESTRICTED, false);
|
||||
auto results = query.NearestPhantomNodes(
|
||||
input, osrm::engine::Approach::UNRESTRICTED, boost::none, 1000, boost::none, false);
|
||||
BOOST_CHECK_EQUAL(results.size(), 1);
|
||||
}
|
||||
|
||||
{
|
||||
auto results = query.NearestPhantomNodesInRange(
|
||||
input, 1000, osrm::engine::Approach::UNRESTRICTED, true);
|
||||
auto results = query.NearestPhantomNodes(
|
||||
input, osrm::engine::Approach::UNRESTRICTED, boost::none, 1000, boost::none, true);
|
||||
BOOST_CHECK_EQUAL(results.size(), 2);
|
||||
}
|
||||
}
|
||||
@ -405,21 +405,30 @@ BOOST_AUTO_TEST_CASE(bearing_tests)
|
||||
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.back().phantom_node.forward_segment_id.id, 0);
|
||||
BOOST_CHECK_EQUAL(results.back().phantom_node.reverse_segment_id.id, 1);
|
||||
}
|
||||
|
||||
{
|
||||
auto results =
|
||||
query.NearestPhantomNodes(input, 5, 270, 10, osrm::engine::Approach::UNRESTRICTED);
|
||||
auto results = query.NearestPhantomNodes(input,
|
||||
osrm::engine::Approach::UNRESTRICTED,
|
||||
5,
|
||||
boost::none,
|
||||
engine::Bearing{270, 10},
|
||||
false);
|
||||
BOOST_CHECK_EQUAL(results.size(), 0);
|
||||
}
|
||||
|
||||
{
|
||||
auto results =
|
||||
query.NearestPhantomNodes(input, 5, 45, 10, osrm::engine::Approach::UNRESTRICTED);
|
||||
auto results = query.NearestPhantomNodes(input,
|
||||
osrm::engine::Approach::UNRESTRICTED,
|
||||
5,
|
||||
boost::none,
|
||||
engine::Bearing{45, 10},
|
||||
false);
|
||||
BOOST_CHECK_EQUAL(results.size(), 2);
|
||||
|
||||
BOOST_CHECK(results[0].phantom_node.forward_segment_id.enabled);
|
||||
@ -432,20 +441,28 @@ BOOST_AUTO_TEST_CASE(bearing_tests)
|
||||
}
|
||||
|
||||
{
|
||||
auto results = query.NearestPhantomNodesInRange(
|
||||
input, 11000, osrm::engine::Approach::UNRESTRICTED, true);
|
||||
auto results = query.NearestPhantomNodes(
|
||||
input, osrm::engine::Approach::UNRESTRICTED, boost::none, 11000, boost::none, true);
|
||||
BOOST_CHECK_EQUAL(results.size(), 2);
|
||||
}
|
||||
|
||||
{
|
||||
auto results = query.NearestPhantomNodesInRange(
|
||||
input, 11000, 270, 10, osrm::engine::Approach::UNRESTRICTED, true);
|
||||
auto results = query.NearestPhantomNodes(input,
|
||||
osrm::engine::Approach::UNRESTRICTED,
|
||||
boost::none,
|
||||
11000,
|
||||
engine::Bearing{270, 10},
|
||||
true);
|
||||
BOOST_CHECK_EQUAL(results.size(), 0);
|
||||
}
|
||||
|
||||
{
|
||||
auto results = query.NearestPhantomNodesInRange(
|
||||
input, 11000, 45, 10, osrm::engine::Approach::UNRESTRICTED, true);
|
||||
auto results = query.NearestPhantomNodes(input,
|
||||
osrm::engine::Approach::UNRESTRICTED,
|
||||
boost::none,
|
||||
11000,
|
||||
engine::Bearing{45, 10},
|
||||
true);
|
||||
BOOST_CHECK_EQUAL(results.size(), 2);
|
||||
|
||||
BOOST_CHECK(results[0].phantom_node.forward_segment_id.enabled);
|
||||
|
Loading…
Reference in New Issue
Block a user