Support snapping to multiple ways at an input location
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
d96960f9cc
@ -49,6 +49,7 @@
|
|||||||
- FIXED: Completed support for no_entry and no_exit turn restrictions. [#5988](https://github.com/Project-OSRM/osrm-backend/pull/5988)
|
- FIXED: Completed support for no_entry and no_exit turn restrictions. [#5988](https://github.com/Project-OSRM/osrm-backend/pull/5988)
|
||||||
- ADDED: Add support for non-round-trips with a single fixed endpoint. [#6050](https://github.com/Project-OSRM/osrm-backend/pull/6050)
|
- ADDED: Add support for non-round-trips with a single fixed endpoint. [#6050](https://github.com/Project-OSRM/osrm-backend/pull/6050)
|
||||||
- FIXED: Improvements to maneuver override processing [#6125](https://github.com/Project-OSRM/osrm-backend/pull/6125)
|
- FIXED: Improvements to maneuver override processing [#6125](https://github.com/Project-OSRM/osrm-backend/pull/6125)
|
||||||
|
- ADDED: Support snapping to multiple ways at an input location. [#5953](https://github.com/Project-OSRM/osrm-backend/pull/5953)
|
||||||
|
|
||||||
# 5.26.0
|
# 5.26.0
|
||||||
- Changes from 5.25.0
|
- Changes from 5.25.0
|
||||||
|
|||||||
@ -28,7 +28,7 @@ Feature: Bicycle - Route around alleys
|
|||||||
|
|
||||||
When I route I should get
|
When I route I should get
|
||||||
| from | to | a:nodes | weight | # |
|
| from | to | a:nodes | weight | # |
|
||||||
| a | f | 1:2:3:6 | 200.4 | Avoids d,e,f |
|
| a | f | 1:2:3:6 | 196.2 | Avoids d,e,f |
|
||||||
| a | e | 1:2:5 | 176.4 | Take the alley b,e if neccessary |
|
| a | e | 1:2:5 | 172.2 | Take the alley b,e if neccessary |
|
||||||
| d | f | 4:1:2:3:6 | 252.6 | Avoids the alley d,e,f |
|
| d | f | 4:1:2:3:6 | 248.4 | Avoids the alley d,e,f |
|
||||||
|
|
||||||
|
|||||||
@ -7,10 +7,10 @@ Feature: Car - Destination only, no passing through
|
|||||||
Scenario: Car - Destination only street
|
Scenario: Car - Destination only street
|
||||||
Given the node map
|
Given the node map
|
||||||
"""
|
"""
|
||||||
a e
|
a e
|
||||||
b c d
|
b1 c 2d
|
||||||
|
|
||||||
x y
|
x y
|
||||||
"""
|
"""
|
||||||
|
|
||||||
And the ways
|
And the ways
|
||||||
@ -23,21 +23,21 @@ Feature: Car - Destination only, no passing through
|
|||||||
When I route I should get
|
When I route I should get
|
||||||
| from | to | route |
|
| from | to | route |
|
||||||
| a | b | ab,ab |
|
| a | b | ab,ab |
|
||||||
| a | c | ab,bcd |
|
| a | c | ab,bcd,bcd |
|
||||||
| a | d | ab,bcd,bcd |
|
| a | 2 | ab,bcd,bcd |
|
||||||
| a | e | axye,axye |
|
| a | e | axye,axye |
|
||||||
| e | d | de,de |
|
| e | d | de,de |
|
||||||
| e | c | de,bcd |
|
| e | c | de,bcd,bcd |
|
||||||
| e | b | de,bcd,bcd |
|
| e | 1 | de,bcd,bcd |
|
||||||
| e | a | axye,axye |
|
| e | a | axye,axye |
|
||||||
|
|
||||||
Scenario: Car - Destination only street
|
Scenario: Car - Destination only street
|
||||||
Given the node map
|
Given the node map
|
||||||
"""
|
"""
|
||||||
a e
|
a e
|
||||||
b c d
|
b1 c 2d
|
||||||
|
|
||||||
x y
|
x y
|
||||||
"""
|
"""
|
||||||
|
|
||||||
And the ways
|
And the ways
|
||||||
@ -51,12 +51,12 @@ Feature: Car - Destination only, no passing through
|
|||||||
When I route I should get
|
When I route I should get
|
||||||
| from | to | route |
|
| from | to | route |
|
||||||
| a | b | ab,ab |
|
| a | b | ab,ab |
|
||||||
| a | c | ab,bc |
|
| a | c | ab,bc,bc |
|
||||||
| a | d | ab,cd |
|
| a | 2 | ab,bc,cd |
|
||||||
| a | e | axye,axye |
|
| a | e | axye,axye |
|
||||||
| e | d | de,de |
|
| e | d | de,de |
|
||||||
| e | c | de,cd |
|
| e | c | de,cd,cd |
|
||||||
| e | b | de,bc |
|
| e | 1 | de,cd,bc |
|
||||||
| e | a | axye,axye |
|
| e | a | axye,axye |
|
||||||
|
|
||||||
Scenario: Car - Routing inside a destination only area
|
Scenario: Car - Routing inside a destination only area
|
||||||
@ -117,6 +117,7 @@ Feature: Car - Destination only, no passing through
|
|||||||
+ \
|
+ \
|
||||||
+ |
|
+ |
|
||||||
d |
|
d |
|
||||||
|
1 |
|
||||||
\___e
|
\___e
|
||||||
"""
|
"""
|
||||||
|
|
||||||
@ -129,7 +130,7 @@ Feature: Car - Destination only, no passing through
|
|||||||
When I route I should get
|
When I route I should get
|
||||||
| from | to | route |
|
| from | to | route |
|
||||||
| e | a | acbe,acbe |
|
| e | a | acbe,acbe |
|
||||||
| d | a | de,acbe,acbe |
|
| 1 | a | de,acbe,acbe |
|
||||||
| c | d | cd,cd |
|
| c | d | cd,cd |
|
||||||
|
|
||||||
Scenario: Car - Routing through a parking lot tagged access=destination,service
|
Scenario: Car - Routing through a parking lot tagged access=destination,service
|
||||||
|
|||||||
@ -411,7 +411,7 @@ Feature: Car - Turn restrictions
|
|||||||
y
|
y
|
||||||
i j f b x a e g h
|
i j f b x a e g h
|
||||||
|
|
||||||
c d
|
c1 d
|
||||||
"""
|
"""
|
||||||
|
|
||||||
And the ways
|
And the ways
|
||||||
@ -438,7 +438,7 @@ Feature: Car - Turn restrictions
|
|||||||
When I route I should get
|
When I route I should get
|
||||||
| from | to | route |
|
| from | to | route |
|
||||||
| e | f | ae,xa,bx,fb,fb |
|
| e | f | ae,xa,bx,fb,fb |
|
||||||
| c | f | dc,da,ae,ge,hg,hg,ge,ae,xa,bx,fb,fb |
|
| 1 | f | dc,da,ae,ge,hg,hg,ge,ae,xa,bx,fb,fb |
|
||||||
| d | f | da,ae,ge,hg,hg,ge,ae,xa,bx,fb,fb |
|
| d | f | da,ae,ge,hg,hg,ge,ae,xa,bx,fb,fb |
|
||||||
|
|
||||||
@except
|
@except
|
||||||
|
|||||||
@ -332,10 +332,11 @@ Feature: Merge Segregated Roads
|
|||||||
|
|
|
|
||||||
.b.
|
.b.
|
||||||
c h
|
c h
|
||||||
|
1 |
|
||||||
|
| 4
|
||||||
| |
|
| |
|
||||||
| |
|
2 |
|
||||||
1 2
|
| 3
|
||||||
| |
|
|
||||||
d g
|
d g
|
||||||
'e'
|
'e'
|
||||||
|
|
|
|
||||||
@ -354,13 +355,13 @@ Feature: Merge Segregated Roads
|
|||||||
| hb | road | yes |
|
| hb | road | yes |
|
||||||
|
|
||||||
When I route I should get
|
When I route I should get
|
||||||
| waypoints | turns | route | intersections |
|
| waypoints | turns | route | intersections |
|
||||||
| a,f | depart,arrive | road,road | true:180,false:0 true:180,false:0 true:180;true:0 |
|
| a,f | depart,arrive | road,road | true:180,false:0 true:180,false:0 true:180;true:0 |
|
||||||
| c,f | depart,arrive | bridge,road | true:180,false:0 true:180;true:0 |
|
|
||||||
| 1,f | depart,arrive | bridge,road | true:180,false:0 true:180;true:0 |
|
| 1,f | depart,arrive | bridge,road | true:180,false:0 true:180;true:0 |
|
||||||
|
| 2,f | depart,arrive | bridge,road | true:180,false:0 true:180;true:0 |
|
||||||
| f,a | depart,arrive | road,road | true:0,true:0 false:180,true:0 false:180;true:180 |
|
| f,a | depart,arrive | road,road | true:0,true:0 false:180,true:0 false:180;true:180 |
|
||||||
| g,a | depart,arrive | bridge,road | true:0,true:0 false:180;true:180 |
|
| 3,a | depart,arrive | bridge,road | true:0,true:0 false:180;true:180 |
|
||||||
| 2,a | depart,arrive | bridge,road | true:0,true:0 false:180;true:180 |
|
| 4,a | depart,arrive | bridge,road | true:0,true:0 false:180;true:180 |
|
||||||
|
|
||||||
@negative
|
@negative
|
||||||
Scenario: Traffic Circle
|
Scenario: Traffic Circle
|
||||||
|
|||||||
@ -67,10 +67,10 @@ Feature: Compass bearing
|
|||||||
Scenario: Bearing in a roundabout
|
Scenario: Bearing in a roundabout
|
||||||
Given the node map
|
Given the node map
|
||||||
"""
|
"""
|
||||||
k d c j
|
k d 1c j
|
||||||
e b
|
e b
|
||||||
f a
|
f a
|
||||||
l g h i
|
l g2 h i
|
||||||
"""
|
"""
|
||||||
|
|
||||||
And the ways
|
And the ways
|
||||||
@ -94,8 +94,8 @@ Feature: Compass bearing
|
|||||||
|
|
||||||
When I route I should get
|
When I route I should get
|
||||||
| from | to | route | bearing |
|
| from | to | route | bearing |
|
||||||
| c | b | cd,de,ef,fg,gh,ha,ab,ab | 0->270,270->225,225->180,180->135,135->90,90->45,45->0,0->0 |
|
| 1 | b | cd,de,ef,fg,gh,ha,ab,ab | 0->270,270->225,225->180,180->135,135->90,90->45,45->0,0->0 |
|
||||||
| g | f | gh,ha,ab,bc,cd,de,ef,ef | 0->90,90->45,45->0,0->315,315->270,270->225,225->180,180->0 |
|
| 2 | f | gh,ha,ab,bc,cd,de,ef,ef | 0->90,90->45,45->0,0->315,315->270,270->225,225->180,180->0 |
|
||||||
|
|
||||||
Scenario: Bearing should stay constant when zig-zagging
|
Scenario: Bearing should stay constant when zig-zagging
|
||||||
Given the node map
|
Given the node map
|
||||||
|
|||||||
@ -589,12 +589,12 @@ Feature: Basic Distance Matrix
|
|||||||
|
|
||||||
When I request a travel distance matrix I should get
|
When I request a travel distance matrix I should get
|
||||||
| | a | b | c | d | e | f |
|
| | a | b | c | d | e | f |
|
||||||
| a | 0 | 100 | 300 | 650 | 1934.5 | 1534.6 |
|
| a | 0 | 100 | 300 | 650 | 660.5 | 1534.6 |
|
||||||
| b | 760.6 | 0 | 200 | 550.1 | 1834.6 | 1434.6 |
|
| b | 760.6 | 0 | 200 | 550.1 | 560.6 | 1434.6 |
|
||||||
| c | 560.6 | 660.5 | 0 | 350 | 1634.6 | 1234.6 |
|
| c | 560.6 | 660.5 | 0 | 350 | 360.5 | 1234.6 |
|
||||||
| d | 1484.6 | 1584.5| 1784.5 | 0 | 1284.5 | 884.6 |
|
| d | 1484.6 | 1584.5| 1645.1 | 0 | 1284.5 | 884.6 |
|
||||||
| e | 200 | 300 | 500 | 710.6 | 0 | 1595.2 |
|
| e | 200 | 300 | 360.5 | 710.6 | 0 | 1595.2 |
|
||||||
| f | 600 | 699.9 | 899.9 | 1110.5 | 399.9 | 0 |
|
| f | 600 | 699.9 | 760.5 | 884.6 | 399.9 | 0 |
|
||||||
|
|
||||||
|
|
||||||
Scenario: Testbot - Filling in noroutes with estimates (defaults to input coordinate location)
|
Scenario: Testbot - Filling in noroutes with estimates (defaults to input coordinate location)
|
||||||
@ -720,11 +720,10 @@ Feature: Basic Distance Matrix
|
|||||||
| 1 | 2 | abcdef,fghij,fghij | 1000.1m |
|
| 1 | 2 | abcdef,fghij,fghij | 1000.1m |
|
||||||
| 1 | 3 | abcdef,fghij,fghij | 1400.1m |
|
| 1 | 3 | abcdef,fghij,fghij | 1400.1m |
|
||||||
| 2 | 3 | fghij,fghij | 400m |
|
| 2 | 3 | fghij,fghij | 400m |
|
||||||
|
|
||||||
|
|
||||||
When I request a travel distance matrix I should get
|
When I request a travel distance matrix I should get
|
||||||
| | 1 | 2 | 3 |
|
| | 1 | 2 | 3 |
|
||||||
| 1 | 0 | 1000.1 | 1400.1 |
|
| 1 | 0 | 1000.1 | 1400.1 |
|
||||||
| 2 | 1000.1 | 0 | 400 |
|
| 2 | 1000.1 | 0 | 400 |
|
||||||
| 3 | 1400.1 | 400 | 0 |
|
| 3 | 1400.1 | 400 | 0 |
|
||||||
|
|
||||||
|
|||||||
@ -491,18 +491,18 @@ Feature: Basic Duration Matrix
|
|||||||
|
|
||||||
When I route I should get
|
When I route I should get
|
||||||
| from | to | route | distance | time | weight |
|
| from | to | route | distance | time | weight |
|
||||||
| a | c | ac,ac | 200m | 5s | 5 |
|
| a | c | ac,ac | 200m | 1s | 1 |
|
||||||
|
|
||||||
When I request a travel time matrix I should get
|
When I request a travel time matrix I should get
|
||||||
| | a | b | c | d |
|
| | a | b | c | d |
|
||||||
| a | 0 | 1 | 5 | 10 |
|
| a | 0 | 1 | 1 | 6 |
|
||||||
|
|
||||||
When I request a travel time matrix I should get
|
When I request a travel time matrix I should get
|
||||||
| | a |
|
| | a |
|
||||||
| a | 0 |
|
| a | 0 |
|
||||||
| b | 1 |
|
| b | 1 |
|
||||||
| c | 15 |
|
| c | 1 |
|
||||||
| d | 10 |
|
| d | 6 |
|
||||||
|
|
||||||
Scenario: Testbot - OneToMany vs ManyToOne
|
Scenario: Testbot - OneToMany vs ManyToOne
|
||||||
Given the node map
|
Given the node map
|
||||||
|
|||||||
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 |
|
| 1 | e | ab,be,be | 36 km/h | 30s +-1 |
|
||||||
| b | f | bc,cf,cf | 36 km/h | 40s +-1 |
|
| b | f | bc,cf,cf | 36 km/h | 40s +-1 |
|
||||||
| 2 | f | bc,cf,cf | 36 km/h | 30s +-1 |
|
| 2 | f | bc,cf,cf | 36 km/h | 30s +-1 |
|
||||||
| c | g | cd,dg,dg | 144 km/h | 10s +-1 |
|
| c | g | cd,dg,dg | 72 km/h | 20s +-1 |
|
||||||
| 3 | g | cd,dg,dg | 54 km/h | 20s +-1 |
|
| 3 | g | cd,dg,dg | 54 km/h | 20s +-1 |
|
||||||
|
|
||||||
Scenario: Weighting based on turn penalty file with weights
|
Scenario: Weighting based on turn penalty file with weights
|
||||||
@ -65,5 +65,5 @@ Feature: Traffic - turn penalties applied to turn onto which a phantom node snap
|
|||||||
| 1 | e | ab,be,be | 36 km/h | 30s +-1 | 6.8,20,0 |
|
| 1 | e | ab,be,be | 36 km/h | 30s +-1 | 6.8,20,0 |
|
||||||
| b | f | bc,cf,cf | 36 km/h | 40s +-1 | 20,20,0 |
|
| b | f | bc,cf,cf | 36 km/h | 40s +-1 | 20,20,0 |
|
||||||
| 2 | f | bc,cf,cf | 36 km/h | 30s +-1 | 10.1,20,0 |
|
| 2 | f | bc,cf,cf | 36 km/h | 30s +-1 | 10.1,20,0 |
|
||||||
| c | g | cd,dg,dg | 144 km/h | 10s +-1 | 120.8,20,0 |
|
| c | g | cd,dg,dg | 72 km/h | 20s +-1 | 120.8,20,0 |
|
||||||
| 3 | g | cd,dg,dg | 54 km/h | 20s +-1 | 110.9,20,0 |
|
| 3 | g | cd,dg,dg | 54 km/h | 20s +-1 | 110.9,20,0 |
|
||||||
|
|||||||
@ -281,7 +281,7 @@ Feature: Weight tests
|
|||||||
|
|
||||||
When I route I should get
|
When I route I should get
|
||||||
| waypoints | route | distance | weights | times |
|
| waypoints | route | distance | weights | times |
|
||||||
| a,c | , | 40m +-.1 | 5.12,0 | 290s,0s |
|
| a,c | , | 40m +-.1 | 2.22,0 | 200s,0s |
|
||||||
| a,e | ,, | 60m +-.1 | 5.12,1.11,0 | 290s,100s,0s |
|
| a,e | ,, | 60m +-.1 | 5.12,1.11,0 | 290s,100s,0s |
|
||||||
| e,a | ,, | 60m +-.1 | 2.21,2.22,0 | 10s,200s,0s |
|
| e,a | ,, | 60m +-.1 | 2.21,2.22,0 | 10s,200s,0s |
|
||||||
| e,d | ,, | 40m +-.1 | 4.01,1.11,0 | 190s,100s,0s |
|
| e,d | ,, | 40m +-.1 | 4.01,1.11,0 | 190s,100s,0s |
|
||||||
|
|||||||
@ -9,9 +9,12 @@
|
|||||||
#include "engine/hint.hpp"
|
#include "engine/hint.hpp"
|
||||||
#include "util/coordinate_calculation.hpp"
|
#include "util/coordinate_calculation.hpp"
|
||||||
|
|
||||||
|
#include <boost/algorithm/string/join.hpp>
|
||||||
#include <boost/assert.hpp>
|
#include <boost/assert.hpp>
|
||||||
|
#include <boost/range/adaptor/transformed.hpp>
|
||||||
#include <boost/range/algorithm/transform.hpp>
|
#include <boost/range/algorithm/transform.hpp>
|
||||||
|
|
||||||
|
#include <boost/range/adaptor/filtered.hpp>
|
||||||
#include <memory>
|
#include <memory>
|
||||||
#include <vector>
|
#include <vector>
|
||||||
|
|
||||||
@ -22,6 +25,8 @@ namespace engine
|
|||||||
namespace api
|
namespace api
|
||||||
{
|
{
|
||||||
|
|
||||||
|
static const constexpr char *INTERSECTION_DELIMITER = " / ";
|
||||||
|
|
||||||
class BaseAPI
|
class BaseAPI
|
||||||
{
|
{
|
||||||
public:
|
public:
|
||||||
@ -30,92 +35,129 @@ class BaseAPI
|
|||||||
{
|
{
|
||||||
}
|
}
|
||||||
|
|
||||||
util::json::Array MakeWaypoints(const std::vector<PhantomNodes> &segment_end_coordinates) const
|
util::json::Array
|
||||||
|
MakeWaypoints(const std::vector<PhantomNodeCandidates> &waypoint_candidates) const
|
||||||
{
|
{
|
||||||
BOOST_ASSERT(parameters.coordinates.size() > 0);
|
BOOST_ASSERT(parameters.coordinates.size() > 0);
|
||||||
BOOST_ASSERT(parameters.coordinates.size() == segment_end_coordinates.size() + 1);
|
BOOST_ASSERT(parameters.coordinates.size() == waypoint_candidates.size());
|
||||||
|
|
||||||
util::json::Array waypoints;
|
util::json::Array waypoints;
|
||||||
waypoints.values.resize(parameters.coordinates.size());
|
waypoints.values.resize(parameters.coordinates.size());
|
||||||
waypoints.values[0] = MakeWaypoint(segment_end_coordinates.front().source_phantom);
|
|
||||||
|
|
||||||
auto out_iter = std::next(waypoints.values.begin());
|
|
||||||
boost::range::transform(
|
boost::range::transform(
|
||||||
segment_end_coordinates, out_iter, [this](const PhantomNodes &phantom_pair) {
|
waypoint_candidates,
|
||||||
return MakeWaypoint(phantom_pair.target_phantom);
|
waypoints.values.begin(),
|
||||||
});
|
[this](const PhantomNodeCandidates &candidates) { return MakeWaypoint(candidates); });
|
||||||
return waypoints;
|
return waypoints;
|
||||||
}
|
}
|
||||||
|
|
||||||
// FIXME: gcc 4.9 does not like MakeWaypoints to be protected
|
// FIXME: gcc 4.9 does not like MakeWaypoints to be protected
|
||||||
// protected:
|
// protected:
|
||||||
util::json::Object MakeWaypoint(const PhantomNode &phantom) const
|
util::json::Object MakeWaypoint(const PhantomNodeCandidates &candidates) const
|
||||||
{
|
{
|
||||||
|
// 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)
|
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(
|
return json::makeWaypoint(
|
||||||
phantom.location,
|
snapped_location,
|
||||||
util::coordinate_calculation::greatCircleDistance(phantom.location,
|
util::coordinate_calculation::greatCircleDistance(snapped_location, input_location),
|
||||||
phantom.input_location),
|
waypoint_name,
|
||||||
facade.GetNameForID(facade.GetNameIndex(phantom.forward_segment_id.id)).to_string(),
|
{std::move(seg_hints)});
|
||||||
Hint{phantom, facade.GetCheckSum()});
|
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
// TODO: check forward/reverse
|
|
||||||
return json::makeWaypoint(
|
return json::makeWaypoint(
|
||||||
phantom.location,
|
snapped_location,
|
||||||
util::coordinate_calculation::greatCircleDistance(phantom.location,
|
util::coordinate_calculation::greatCircleDistance(snapped_location, input_location),
|
||||||
phantom.input_location),
|
waypoint_name);
|
||||||
facade.GetNameForID(facade.GetNameIndex(phantom.forward_segment_id.id))
|
|
||||||
.to_string());
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
flatbuffers::Offset<flatbuffers::Vector<flatbuffers::Offset<fbresult::Waypoint>>>
|
flatbuffers::Offset<flatbuffers::Vector<flatbuffers::Offset<fbresult::Waypoint>>>
|
||||||
MakeWaypoints(flatbuffers::FlatBufferBuilder *builder,
|
MakeWaypoints(flatbuffers::FlatBufferBuilder *builder,
|
||||||
const std::vector<PhantomNodes> &segment_end_coordinates) const
|
const std::vector<PhantomNodeCandidates> &waypoint_candidates) const
|
||||||
{
|
{
|
||||||
BOOST_ASSERT(parameters.coordinates.size() > 0);
|
BOOST_ASSERT(parameters.coordinates.size() > 0);
|
||||||
BOOST_ASSERT(parameters.coordinates.size() == segment_end_coordinates.size() + 1);
|
BOOST_ASSERT(parameters.coordinates.size() == waypoint_candidates.size());
|
||||||
|
|
||||||
std::vector<flatbuffers::Offset<fbresult::Waypoint>> waypoints;
|
std::vector<flatbuffers::Offset<fbresult::Waypoint>> waypoints;
|
||||||
waypoints.resize(parameters.coordinates.size());
|
waypoints.resize(parameters.coordinates.size());
|
||||||
waypoints[0] =
|
|
||||||
MakeWaypoint(builder, segment_end_coordinates.front().source_phantom)->Finish();
|
|
||||||
|
|
||||||
std::transform(segment_end_coordinates.begin(),
|
std::transform(waypoint_candidates.begin(),
|
||||||
segment_end_coordinates.end(),
|
waypoint_candidates.end(),
|
||||||
std::next(waypoints.begin()),
|
waypoints.begin(),
|
||||||
[this, builder](const PhantomNodes &phantom_pair) {
|
[this, builder](const PhantomNodeCandidates &candidates) {
|
||||||
return MakeWaypoint(builder, phantom_pair.target_phantom)->Finish();
|
return MakeWaypoint(builder, candidates)->Finish();
|
||||||
});
|
});
|
||||||
return builder->CreateVector(waypoints);
|
return builder->CreateVector(waypoints);
|
||||||
}
|
}
|
||||||
|
|
||||||
// FIXME: gcc 4.9 does not like MakeWaypoints to be protected
|
// FIXME: gcc 4.9 does not like MakeWaypoints to be protected
|
||||||
// protected:
|
// protected:
|
||||||
std::unique_ptr<fbresult::WaypointBuilder> MakeWaypoint(flatbuffers::FlatBufferBuilder *builder,
|
std::unique_ptr<fbresult::WaypointBuilder>
|
||||||
const PhantomNode &phantom) const
|
MakeWaypoint(flatbuffers::FlatBufferBuilder *builder,
|
||||||
|
const PhantomNodeCandidates &candidates) const
|
||||||
{
|
{
|
||||||
|
|
||||||
|
const auto &snapped_location = candidatesSnappedLocation(candidates);
|
||||||
|
const auto &input_location = candidatesInputLocation(candidates);
|
||||||
auto location =
|
auto location =
|
||||||
fbresult::Position(static_cast<double>(util::toFloating(phantom.location.lon)),
|
fbresult::Position(static_cast<double>(util::toFloating(snapped_location.lon)),
|
||||||
static_cast<double>(util::toFloating(phantom.location.lat)));
|
static_cast<double>(util::toFloating(snapped_location.lat)));
|
||||||
auto name_string = builder->CreateString(
|
|
||||||
facade.GetNameForID(facade.GetNameIndex(phantom.forward_segment_id.id)).to_string());
|
const auto toName = [this](const auto &phantom) {
|
||||||
|
return facade.GetNameForID(facade.GetNameIndex(phantom.forward_segment_id.id))
|
||||||
|
.to_string();
|
||||||
|
};
|
||||||
|
const auto noEmpty = [](const auto &name) { return !name.empty(); };
|
||||||
|
|
||||||
|
// At an intersection we may have multiple phantom node candidates.
|
||||||
|
// Combine them to represent the waypoint name.
|
||||||
|
std::string waypoint_name = boost::algorithm::join(
|
||||||
|
candidates | boost::adaptors::transformed(toName) | boost::adaptors::filtered(noEmpty),
|
||||||
|
INTERSECTION_DELIMITER);
|
||||||
|
auto name_string = builder->CreateString(waypoint_name);
|
||||||
|
|
||||||
flatbuffers::Offset<flatbuffers::String> hint_string;
|
flatbuffers::Offset<flatbuffers::String> hint_string;
|
||||||
if (parameters.generate_hints)
|
if (parameters.generate_hints)
|
||||||
{
|
{
|
||||||
hint_string = builder->CreateString(Hint{phantom, facade.GetCheckSum()}.ToBase64());
|
std::vector<SegmentHint> seg_hints(candidates.size());
|
||||||
|
std::transform(candidates.begin(),
|
||||||
|
candidates.end(),
|
||||||
|
seg_hints.begin(),
|
||||||
|
[this](const auto &phantom) {
|
||||||
|
return SegmentHint{phantom, facade.GetCheckSum()};
|
||||||
|
});
|
||||||
|
Hint hint{std::move(seg_hints)};
|
||||||
|
hint_string = builder->CreateString(hint.ToBase64());
|
||||||
}
|
}
|
||||||
|
|
||||||
auto waypoint = std::make_unique<fbresult::WaypointBuilder>(*builder);
|
auto waypoint = std::make_unique<fbresult::WaypointBuilder>(*builder);
|
||||||
waypoint->add_location(&location);
|
waypoint->add_location(&location);
|
||||||
waypoint->add_distance(util::coordinate_calculation::greatCircleDistance(
|
waypoint->add_distance(
|
||||||
phantom.location, phantom.input_location));
|
util::coordinate_calculation::greatCircleDistance(snapped_location, input_location));
|
||||||
waypoint->add_name(name_string);
|
waypoint->add_name(name_string);
|
||||||
if (parameters.generate_hints)
|
if (parameters.generate_hints)
|
||||||
{
|
{
|
||||||
|
|||||||
@ -51,14 +51,14 @@ namespace api
|
|||||||
* Holds member attributes:
|
* Holds member attributes:
|
||||||
* - coordinates: for specifying location(s) to services
|
* - coordinates: for specifying location(s) to services
|
||||||
* - hints: hint for the service to derive the position(s) in the road network more efficiently,
|
* - hints: hint for the service to derive the position(s) in the road network more efficiently,
|
||||||
* optional per coordinate
|
* optional per coordinate. Multiple hints can be provided for a coordinate.
|
||||||
* - radiuses: limits the search for segments in the road network to given radius(es) in meter,
|
* - radiuses: limits the search for segments in the road network to given radius(es) in meter,
|
||||||
* optional per coordinate
|
* optional per coordinate
|
||||||
* - bearings: limits the search for segments in the road network to given bearing(s) in degree
|
* - bearings: limits the search for segments in the road network to given bearing(s) in degree
|
||||||
* towards true north in clockwise direction, optional per coordinate
|
* towards true north in clockwise direction, optional per coordinate
|
||||||
* - approaches: force the phantom node to start towards the node with the road country side.
|
* - approaches: force the phantom node to start towards the node with the road country side.
|
||||||
*
|
*
|
||||||
* \see OSRM, Coordinate, Hint, Bearing, RouteParame, RouteParameters, TableParameters,
|
* \see OSRM, Coordinate, Hint, Bearing, RouteParameters, TableParameters,
|
||||||
* NearestParameters, TripParameters, MatchParameters and TileParameters
|
* NearestParameters, TripParameters, MatchParameters and TileParameters
|
||||||
*/
|
*/
|
||||||
struct BaseParameters
|
struct BaseParameters
|
||||||
|
|||||||
@ -76,7 +76,7 @@ class MatchAPI final : public RouteAPI
|
|||||||
routes.values.reserve(number_of_routes);
|
routes.values.reserve(number_of_routes);
|
||||||
for (auto index : util::irange<std::size_t>(0UL, sub_matchings.size()))
|
for (auto index : util::irange<std::size_t>(0UL, sub_matchings.size()))
|
||||||
{
|
{
|
||||||
auto route = MakeRoute(sub_routes[index].segment_end_coordinates,
|
auto route = MakeRoute(sub_routes[index].leg_endpoints,
|
||||||
sub_routes[index].unpacked_path_segments,
|
sub_routes[index].unpacked_path_segments,
|
||||||
sub_routes[index].source_traversed_in_reverse,
|
sub_routes[index].source_traversed_in_reverse,
|
||||||
sub_routes[index].target_traversed_in_reverse);
|
sub_routes[index].target_traversed_in_reverse);
|
||||||
@ -146,7 +146,7 @@ class MatchAPI final : public RouteAPI
|
|||||||
}
|
}
|
||||||
const auto &phantom =
|
const auto &phantom =
|
||||||
sub_matchings[matching_index.sub_matching_index].nodes[matching_index.point_index];
|
sub_matchings[matching_index.sub_matching_index].nodes[matching_index.point_index];
|
||||||
auto waypoint = BaseAPI::MakeWaypoint(&fb_result, phantom);
|
auto waypoint = BaseAPI::MakeWaypoint(&fb_result, {phantom});
|
||||||
waypoint->add_matchings_index(matching_index.sub_matching_index);
|
waypoint->add_matchings_index(matching_index.sub_matching_index);
|
||||||
waypoint->add_alternatives_count(sub_matchings[matching_index.sub_matching_index]
|
waypoint->add_alternatives_count(sub_matchings[matching_index.sub_matching_index]
|
||||||
.alternatives_count[matching_index.point_index]);
|
.alternatives_count[matching_index.point_index]);
|
||||||
@ -200,7 +200,7 @@ class MatchAPI final : public RouteAPI
|
|||||||
}
|
}
|
||||||
const auto &phantom =
|
const auto &phantom =
|
||||||
sub_matchings[matching_index.sub_matching_index].nodes[matching_index.point_index];
|
sub_matchings[matching_index.sub_matching_index].nodes[matching_index.point_index];
|
||||||
auto waypoint = BaseAPI::MakeWaypoint(phantom);
|
auto waypoint = BaseAPI::MakeWaypoint({phantom});
|
||||||
waypoint.values["matchings_index"] = matching_index.sub_matching_index;
|
waypoint.values["matchings_index"] = matching_index.sub_matching_index;
|
||||||
waypoint.values["waypoint_index"] = matching_index.point_index;
|
waypoint.values["waypoint_index"] = matching_index.point_index;
|
||||||
waypoint.values["alternatives_count"] =
|
waypoint.values["alternatives_count"] =
|
||||||
|
|||||||
@ -71,7 +71,7 @@ class NearestAPI final : public BaseAPI
|
|||||||
auto node_values = MakeNodes(phantom_node);
|
auto node_values = MakeNodes(phantom_node);
|
||||||
fbresult::Uint64Pair nodes{node_values.first, node_values.second};
|
fbresult::Uint64Pair nodes{node_values.first, node_values.second};
|
||||||
|
|
||||||
auto waypoint = MakeWaypoint(&fb_result, phantom_node);
|
auto waypoint = MakeWaypoint(&fb_result, {phantom_node});
|
||||||
waypoint->add_nodes(&nodes);
|
waypoint->add_nodes(&nodes);
|
||||||
return waypoint->Finish();
|
return waypoint->Finish();
|
||||||
});
|
});
|
||||||
@ -100,7 +100,7 @@ class NearestAPI final : public BaseAPI
|
|||||||
waypoints.values.begin(),
|
waypoints.values.begin(),
|
||||||
[this](const PhantomNodeWithDistance &phantom_with_distance) {
|
[this](const PhantomNodeWithDistance &phantom_with_distance) {
|
||||||
auto &phantom_node = phantom_with_distance.phantom_node;
|
auto &phantom_node = phantom_with_distance.phantom_node;
|
||||||
auto waypoint = MakeWaypoint(phantom_node);
|
auto waypoint = MakeWaypoint({phantom_node});
|
||||||
|
|
||||||
util::json::Array nodes;
|
util::json::Array nodes;
|
||||||
|
|
||||||
|
|||||||
@ -47,8 +47,8 @@ class RouteAPI : public BaseAPI
|
|||||||
|
|
||||||
void
|
void
|
||||||
MakeResponse(const InternalManyRoutesResult &raw_routes,
|
MakeResponse(const InternalManyRoutesResult &raw_routes,
|
||||||
const std::vector<PhantomNodes>
|
const std::vector<PhantomNodeCandidates>
|
||||||
&all_start_end_points, // all used coordinates, ignoring waypoints= parameter
|
&waypoint_candidates, // all used coordinates, ignoring waypoints= parameter
|
||||||
osrm::engine::api::ResultT &response) const
|
osrm::engine::api::ResultT &response) const
|
||||||
{
|
{
|
||||||
BOOST_ASSERT(!raw_routes.routes.empty());
|
BOOST_ASSERT(!raw_routes.routes.empty());
|
||||||
@ -56,19 +56,19 @@ class RouteAPI : public BaseAPI
|
|||||||
if (response.is<flatbuffers::FlatBufferBuilder>())
|
if (response.is<flatbuffers::FlatBufferBuilder>())
|
||||||
{
|
{
|
||||||
auto &fb_result = response.get<flatbuffers::FlatBufferBuilder>();
|
auto &fb_result = response.get<flatbuffers::FlatBufferBuilder>();
|
||||||
MakeResponse(raw_routes, all_start_end_points, fb_result);
|
MakeResponse(raw_routes, waypoint_candidates, fb_result);
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
auto &json_result = response.get<util::json::Object>();
|
auto &json_result = response.get<util::json::Object>();
|
||||||
MakeResponse(raw_routes, all_start_end_points, json_result);
|
MakeResponse(raw_routes, waypoint_candidates, json_result);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void
|
void
|
||||||
MakeResponse(const InternalManyRoutesResult &raw_routes,
|
MakeResponse(const InternalManyRoutesResult &raw_routes,
|
||||||
const std::vector<PhantomNodes>
|
const std::vector<PhantomNodeCandidates>
|
||||||
&all_start_end_points, // all used coordinates, ignoring waypoints= parameter
|
&waypoint_candidates, // all used coordinates, ignoring waypoints= parameter
|
||||||
flatbuffers::FlatBufferBuilder &fb_result) const
|
flatbuffers::FlatBufferBuilder &fb_result) const
|
||||||
{
|
{
|
||||||
|
|
||||||
@ -80,8 +80,8 @@ class RouteAPI : public BaseAPI
|
|||||||
}
|
}
|
||||||
|
|
||||||
auto response =
|
auto response =
|
||||||
MakeFBResponse(raw_routes, fb_result, [this, &all_start_end_points, &fb_result]() {
|
MakeFBResponse(raw_routes, fb_result, [this, &waypoint_candidates, &fb_result]() {
|
||||||
return BaseAPI::MakeWaypoints(&fb_result, all_start_end_points);
|
return BaseAPI::MakeWaypoints(&fb_result, waypoint_candidates);
|
||||||
});
|
});
|
||||||
|
|
||||||
if (!data_timestamp.empty())
|
if (!data_timestamp.empty())
|
||||||
@ -93,8 +93,8 @@ class RouteAPI : public BaseAPI
|
|||||||
|
|
||||||
void
|
void
|
||||||
MakeResponse(const InternalManyRoutesResult &raw_routes,
|
MakeResponse(const InternalManyRoutesResult &raw_routes,
|
||||||
const std::vector<PhantomNodes>
|
const std::vector<PhantomNodeCandidates>
|
||||||
&all_start_end_points, // all used coordinates, ignoring waypoints= parameter
|
&waypoint_candidates, // all used coordinates, ignoring waypoints= parameter
|
||||||
util::json::Object &response) const
|
util::json::Object &response) const
|
||||||
{
|
{
|
||||||
util::json::Array jsRoutes;
|
util::json::Array jsRoutes;
|
||||||
@ -104,7 +104,7 @@ class RouteAPI : public BaseAPI
|
|||||||
if (!route.is_valid())
|
if (!route.is_valid())
|
||||||
continue;
|
continue;
|
||||||
|
|
||||||
jsRoutes.values.push_back(MakeRoute(route.segment_end_coordinates,
|
jsRoutes.values.push_back(MakeRoute(route.leg_endpoints,
|
||||||
route.unpacked_path_segments,
|
route.unpacked_path_segments,
|
||||||
route.source_traversed_in_reverse,
|
route.source_traversed_in_reverse,
|
||||||
route.target_traversed_in_reverse));
|
route.target_traversed_in_reverse));
|
||||||
@ -112,7 +112,7 @@ class RouteAPI : public BaseAPI
|
|||||||
|
|
||||||
if (!parameters.skip_waypoints)
|
if (!parameters.skip_waypoints)
|
||||||
{
|
{
|
||||||
response.values["waypoints"] = BaseAPI::MakeWaypoints(all_start_end_points);
|
response.values["waypoints"] = BaseAPI::MakeWaypoints(waypoint_candidates);
|
||||||
}
|
}
|
||||||
response.values["routes"] = std::move(jsRoutes);
|
response.values["routes"] = std::move(jsRoutes);
|
||||||
response.values["code"] = "Ok";
|
response.values["code"] = "Ok";
|
||||||
@ -138,7 +138,7 @@ class RouteAPI : public BaseAPI
|
|||||||
continue;
|
continue;
|
||||||
|
|
||||||
routes.push_back(MakeRoute(fb_result,
|
routes.push_back(MakeRoute(fb_result,
|
||||||
raw_route.segment_end_coordinates,
|
raw_route.leg_endpoints,
|
||||||
raw_route.unpacked_path_segments,
|
raw_route.unpacked_path_segments,
|
||||||
raw_route.source_traversed_in_reverse,
|
raw_route.source_traversed_in_reverse,
|
||||||
raw_route.target_traversed_in_reverse));
|
raw_route.target_traversed_in_reverse));
|
||||||
@ -328,12 +328,12 @@ class RouteAPI : public BaseAPI
|
|||||||
|
|
||||||
flatbuffers::Offset<fbresult::RouteObject>
|
flatbuffers::Offset<fbresult::RouteObject>
|
||||||
MakeRoute(flatbuffers::FlatBufferBuilder &fb_result,
|
MakeRoute(flatbuffers::FlatBufferBuilder &fb_result,
|
||||||
const std::vector<PhantomNodes> &segment_end_coordinates,
|
const std::vector<PhantomEndpoints> &leg_endpoints,
|
||||||
const std::vector<std::vector<PathData>> &unpacked_path_segments,
|
const std::vector<std::vector<PathData>> &unpacked_path_segments,
|
||||||
const std::vector<bool> &source_traversed_in_reverse,
|
const std::vector<bool> &source_traversed_in_reverse,
|
||||||
const std::vector<bool> &target_traversed_in_reverse) const
|
const std::vector<bool> &target_traversed_in_reverse) const
|
||||||
{
|
{
|
||||||
auto legs_info = MakeLegs(segment_end_coordinates,
|
auto legs_info = MakeLegs(leg_endpoints,
|
||||||
unpacked_path_segments,
|
unpacked_path_segments,
|
||||||
source_traversed_in_reverse,
|
source_traversed_in_reverse,
|
||||||
target_traversed_in_reverse);
|
target_traversed_in_reverse);
|
||||||
@ -705,12 +705,12 @@ class RouteAPI : public BaseAPI
|
|||||||
return fb_result.CreateVector(intersections);
|
return fb_result.CreateVector(intersections);
|
||||||
}
|
}
|
||||||
|
|
||||||
util::json::Object MakeRoute(const std::vector<PhantomNodes> &segment_end_coordinates,
|
util::json::Object MakeRoute(const std::vector<PhantomEndpoints> &leg_endpoints,
|
||||||
const std::vector<std::vector<PathData>> &unpacked_path_segments,
|
const std::vector<std::vector<PathData>> &unpacked_path_segments,
|
||||||
const std::vector<bool> &source_traversed_in_reverse,
|
const std::vector<bool> &source_traversed_in_reverse,
|
||||||
const std::vector<bool> &target_traversed_in_reverse) const
|
const std::vector<bool> &target_traversed_in_reverse) const
|
||||||
{
|
{
|
||||||
auto legs_info = MakeLegs(segment_end_coordinates,
|
auto legs_info = MakeLegs(leg_endpoints,
|
||||||
unpacked_path_segments,
|
unpacked_path_segments,
|
||||||
source_traversed_in_reverse,
|
source_traversed_in_reverse,
|
||||||
target_traversed_in_reverse);
|
target_traversed_in_reverse);
|
||||||
@ -868,7 +868,7 @@ class RouteAPI : public BaseAPI
|
|||||||
const RouteParameters ¶meters;
|
const RouteParameters ¶meters;
|
||||||
|
|
||||||
std::pair<std::vector<guidance::RouteLeg>, std::vector<guidance::LegGeometry>>
|
std::pair<std::vector<guidance::RouteLeg>, std::vector<guidance::LegGeometry>>
|
||||||
MakeLegs(const std::vector<PhantomNodes> &segment_end_coordinates,
|
MakeLegs(const std::vector<PhantomEndpoints> &leg_endpoints,
|
||||||
const std::vector<std::vector<PathData>> &unpacked_path_segments,
|
const std::vector<std::vector<PathData>> &unpacked_path_segments,
|
||||||
const std::vector<bool> &source_traversed_in_reverse,
|
const std::vector<bool> &source_traversed_in_reverse,
|
||||||
const std::vector<bool> &target_traversed_in_reverse) const
|
const std::vector<bool> &target_traversed_in_reverse) const
|
||||||
@ -877,13 +877,13 @@ class RouteAPI : public BaseAPI
|
|||||||
std::make_pair(std::vector<guidance::RouteLeg>(), std::vector<guidance::LegGeometry>());
|
std::make_pair(std::vector<guidance::RouteLeg>(), std::vector<guidance::LegGeometry>());
|
||||||
auto &legs = result.first;
|
auto &legs = result.first;
|
||||||
auto &leg_geometries = result.second;
|
auto &leg_geometries = result.second;
|
||||||
auto number_of_legs = segment_end_coordinates.size();
|
auto number_of_legs = leg_endpoints.size();
|
||||||
legs.reserve(number_of_legs);
|
legs.reserve(number_of_legs);
|
||||||
leg_geometries.reserve(number_of_legs);
|
leg_geometries.reserve(number_of_legs);
|
||||||
|
|
||||||
for (auto idx : util::irange<std::size_t>(0UL, number_of_legs))
|
for (auto idx : util::irange<std::size_t>(0UL, number_of_legs))
|
||||||
{
|
{
|
||||||
const auto &phantoms = segment_end_coordinates[idx];
|
const auto &phantoms = leg_endpoints[idx];
|
||||||
const auto &path_data = unpacked_path_segments[idx];
|
const auto &path_data = unpacked_path_segments[idx];
|
||||||
|
|
||||||
const bool reversed_source = source_traversed_in_reverse[idx];
|
const bool reversed_source = source_traversed_in_reverse[idx];
|
||||||
|
|||||||
@ -48,25 +48,25 @@ class TableAPI final : public BaseAPI
|
|||||||
|
|
||||||
virtual void
|
virtual void
|
||||||
MakeResponse(const std::pair<std::vector<EdgeDuration>, std::vector<EdgeDistance>> &tables,
|
MakeResponse(const std::pair<std::vector<EdgeDuration>, std::vector<EdgeDistance>> &tables,
|
||||||
const std::vector<PhantomNode> &phantoms,
|
const std::vector<PhantomNodeCandidates> &candidates,
|
||||||
const std::vector<TableCellRef> &fallback_speed_cells,
|
const std::vector<TableCellRef> &fallback_speed_cells,
|
||||||
osrm::engine::api::ResultT &response) const
|
osrm::engine::api::ResultT &response) const
|
||||||
{
|
{
|
||||||
if (response.is<flatbuffers::FlatBufferBuilder>())
|
if (response.is<flatbuffers::FlatBufferBuilder>())
|
||||||
{
|
{
|
||||||
auto &fb_result = response.get<flatbuffers::FlatBufferBuilder>();
|
auto &fb_result = response.get<flatbuffers::FlatBufferBuilder>();
|
||||||
MakeResponse(tables, phantoms, fallback_speed_cells, fb_result);
|
MakeResponse(tables, candidates, fallback_speed_cells, fb_result);
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
auto &json_result = response.get<util::json::Object>();
|
auto &json_result = response.get<util::json::Object>();
|
||||||
MakeResponse(tables, phantoms, fallback_speed_cells, json_result);
|
MakeResponse(tables, candidates, fallback_speed_cells, json_result);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
virtual void
|
virtual void
|
||||||
MakeResponse(const std::pair<std::vector<EdgeDuration>, std::vector<EdgeDistance>> &tables,
|
MakeResponse(const std::pair<std::vector<EdgeDuration>, std::vector<EdgeDistance>> &tables,
|
||||||
const std::vector<PhantomNode> &phantoms,
|
const std::vector<PhantomNodeCandidates> &candidates,
|
||||||
const std::vector<TableCellRef> &fallback_speed_cells,
|
const std::vector<TableCellRef> &fallback_speed_cells,
|
||||||
flatbuffers::FlatBufferBuilder &fb_result) const
|
flatbuffers::FlatBufferBuilder &fb_result) const
|
||||||
{
|
{
|
||||||
@ -86,15 +86,15 @@ class TableAPI final : public BaseAPI
|
|||||||
{
|
{
|
||||||
if (!parameters.skip_waypoints)
|
if (!parameters.skip_waypoints)
|
||||||
{
|
{
|
||||||
sources = MakeWaypoints(fb_result, phantoms);
|
sources = MakeWaypoints(fb_result, candidates);
|
||||||
}
|
}
|
||||||
number_of_sources = phantoms.size();
|
number_of_sources = candidates.size();
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
if (!parameters.skip_waypoints)
|
if (!parameters.skip_waypoints)
|
||||||
{
|
{
|
||||||
sources = MakeWaypoints(fb_result, phantoms, parameters.sources);
|
sources = MakeWaypoints(fb_result, candidates, parameters.sources);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -104,15 +104,15 @@ class TableAPI final : public BaseAPI
|
|||||||
{
|
{
|
||||||
if (!parameters.skip_waypoints)
|
if (!parameters.skip_waypoints)
|
||||||
{
|
{
|
||||||
destinations = MakeWaypoints(fb_result, phantoms);
|
destinations = MakeWaypoints(fb_result, candidates);
|
||||||
}
|
}
|
||||||
number_of_destinations = phantoms.size();
|
number_of_destinations = candidates.size();
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
if (!parameters.skip_waypoints)
|
if (!parameters.skip_waypoints)
|
||||||
{
|
{
|
||||||
destinations = MakeWaypoints(fb_result, phantoms, parameters.destinations);
|
destinations = MakeWaypoints(fb_result, candidates, parameters.destinations);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -168,7 +168,7 @@ class TableAPI final : public BaseAPI
|
|||||||
|
|
||||||
virtual void
|
virtual void
|
||||||
MakeResponse(const std::pair<std::vector<EdgeDuration>, std::vector<EdgeDistance>> &tables,
|
MakeResponse(const std::pair<std::vector<EdgeDuration>, std::vector<EdgeDistance>> &tables,
|
||||||
const std::vector<PhantomNode> &phantoms,
|
const std::vector<PhantomNodeCandidates> &candidates,
|
||||||
const std::vector<TableCellRef> &fallback_speed_cells,
|
const std::vector<TableCellRef> &fallback_speed_cells,
|
||||||
util::json::Object &response) const
|
util::json::Object &response) const
|
||||||
{
|
{
|
||||||
@ -180,15 +180,15 @@ class TableAPI final : public BaseAPI
|
|||||||
{
|
{
|
||||||
if (!parameters.skip_waypoints)
|
if (!parameters.skip_waypoints)
|
||||||
{
|
{
|
||||||
response.values["sources"] = MakeWaypoints(phantoms);
|
response.values["sources"] = MakeWaypoints(candidates);
|
||||||
}
|
}
|
||||||
number_of_sources = phantoms.size();
|
number_of_sources = candidates.size();
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
if (!parameters.skip_waypoints)
|
if (!parameters.skip_waypoints)
|
||||||
{
|
{
|
||||||
response.values["sources"] = MakeWaypoints(phantoms, parameters.sources);
|
response.values["sources"] = MakeWaypoints(candidates, parameters.sources);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -196,15 +196,16 @@ class TableAPI final : public BaseAPI
|
|||||||
{
|
{
|
||||||
if (!parameters.skip_waypoints)
|
if (!parameters.skip_waypoints)
|
||||||
{
|
{
|
||||||
response.values["destinations"] = MakeWaypoints(phantoms);
|
response.values["destinations"] = MakeWaypoints(candidates);
|
||||||
}
|
}
|
||||||
number_of_destinations = phantoms.size();
|
number_of_destinations = candidates.size();
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
if (!parameters.skip_waypoints)
|
if (!parameters.skip_waypoints)
|
||||||
{
|
{
|
||||||
response.values["destinations"] = MakeWaypoints(phantoms, parameters.destinations);
|
response.values["destinations"] =
|
||||||
|
MakeWaypoints(candidates, parameters.destinations);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -236,32 +237,34 @@ class TableAPI final : public BaseAPI
|
|||||||
protected:
|
protected:
|
||||||
virtual flatbuffers::Offset<flatbuffers::Vector<flatbuffers::Offset<fbresult::Waypoint>>>
|
virtual flatbuffers::Offset<flatbuffers::Vector<flatbuffers::Offset<fbresult::Waypoint>>>
|
||||||
MakeWaypoints(flatbuffers::FlatBufferBuilder &builder,
|
MakeWaypoints(flatbuffers::FlatBufferBuilder &builder,
|
||||||
const std::vector<PhantomNode> &phantoms) const
|
const std::vector<PhantomNodeCandidates> &candidates) const
|
||||||
{
|
{
|
||||||
std::vector<flatbuffers::Offset<fbresult::Waypoint>> waypoints;
|
std::vector<flatbuffers::Offset<fbresult::Waypoint>> waypoints;
|
||||||
waypoints.reserve(phantoms.size());
|
waypoints.reserve(candidates.size());
|
||||||
BOOST_ASSERT(phantoms.size() == parameters.coordinates.size());
|
BOOST_ASSERT(candidates.size() == parameters.coordinates.size());
|
||||||
|
|
||||||
boost::range::transform(
|
boost::range::transform(candidates,
|
||||||
phantoms, std::back_inserter(waypoints), [this, &builder](const PhantomNode &phantom) {
|
std::back_inserter(waypoints),
|
||||||
return BaseAPI::MakeWaypoint(&builder, phantom)->Finish();
|
[this, &builder](const PhantomNodeCandidates &candidates) {
|
||||||
});
|
return BaseAPI::MakeWaypoint(&builder, candidates)->Finish();
|
||||||
|
});
|
||||||
return builder.CreateVector(waypoints);
|
return builder.CreateVector(waypoints);
|
||||||
}
|
}
|
||||||
|
|
||||||
virtual flatbuffers::Offset<flatbuffers::Vector<flatbuffers::Offset<fbresult::Waypoint>>>
|
virtual flatbuffers::Offset<flatbuffers::Vector<flatbuffers::Offset<fbresult::Waypoint>>>
|
||||||
MakeWaypoints(flatbuffers::FlatBufferBuilder &builder,
|
MakeWaypoints(flatbuffers::FlatBufferBuilder &builder,
|
||||||
const std::vector<PhantomNode> &phantoms,
|
const std::vector<PhantomNodeCandidates> &candidates,
|
||||||
const std::vector<std::size_t> &indices) const
|
const std::vector<std::size_t> &indices) const
|
||||||
{
|
{
|
||||||
std::vector<flatbuffers::Offset<fbresult::Waypoint>> waypoints;
|
std::vector<flatbuffers::Offset<fbresult::Waypoint>> waypoints;
|
||||||
waypoints.reserve(indices.size());
|
waypoints.reserve(indices.size());
|
||||||
boost::range::transform(indices,
|
boost::range::transform(
|
||||||
std::back_inserter(waypoints),
|
indices,
|
||||||
[this, &builder, phantoms](const std::size_t idx) {
|
std::back_inserter(waypoints),
|
||||||
BOOST_ASSERT(idx < phantoms.size());
|
[this, &builder, &candidates](const std::size_t idx) {
|
||||||
return BaseAPI::MakeWaypoint(&builder, phantoms[idx])->Finish();
|
BOOST_ASSERT(idx < candidates.size());
|
||||||
});
|
return BaseAPI::MakeWaypoint(&builder, candidates[idx])->Finish();
|
||||||
|
});
|
||||||
return builder.CreateVector(waypoints);
|
return builder.CreateVector(waypoints);
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -313,29 +316,31 @@ class TableAPI final : public BaseAPI
|
|||||||
return builder.CreateVector(fb_table);
|
return builder.CreateVector(fb_table);
|
||||||
}
|
}
|
||||||
|
|
||||||
virtual util::json::Array MakeWaypoints(const std::vector<PhantomNode> &phantoms) const
|
virtual util::json::Array
|
||||||
|
MakeWaypoints(const std::vector<PhantomNodeCandidates> &candidates) const
|
||||||
{
|
{
|
||||||
util::json::Array json_waypoints;
|
util::json::Array json_waypoints;
|
||||||
json_waypoints.values.reserve(phantoms.size());
|
json_waypoints.values.reserve(candidates.size());
|
||||||
BOOST_ASSERT(phantoms.size() == parameters.coordinates.size());
|
BOOST_ASSERT(candidates.size() == parameters.coordinates.size());
|
||||||
|
|
||||||
boost::range::transform(
|
boost::range::transform(candidates,
|
||||||
phantoms,
|
std::back_inserter(json_waypoints.values),
|
||||||
std::back_inserter(json_waypoints.values),
|
[this](const PhantomNodeCandidates &candidates) {
|
||||||
[this](const PhantomNode &phantom) { return BaseAPI::MakeWaypoint(phantom); });
|
return BaseAPI::MakeWaypoint(candidates);
|
||||||
|
});
|
||||||
return json_waypoints;
|
return json_waypoints;
|
||||||
}
|
}
|
||||||
|
|
||||||
virtual util::json::Array MakeWaypoints(const std::vector<PhantomNode> &phantoms,
|
virtual util::json::Array MakeWaypoints(const std::vector<PhantomNodeCandidates> &candidates,
|
||||||
const std::vector<std::size_t> &indices) const
|
const std::vector<std::size_t> &indices) const
|
||||||
{
|
{
|
||||||
util::json::Array json_waypoints;
|
util::json::Array json_waypoints;
|
||||||
json_waypoints.values.reserve(indices.size());
|
json_waypoints.values.reserve(indices.size());
|
||||||
boost::range::transform(indices,
|
boost::range::transform(indices,
|
||||||
std::back_inserter(json_waypoints.values),
|
std::back_inserter(json_waypoints.values),
|
||||||
[this, phantoms](const std::size_t idx) {
|
[this, &candidates](const std::size_t idx) {
|
||||||
BOOST_ASSERT(idx < phantoms.size());
|
BOOST_ASSERT(idx < candidates.size());
|
||||||
return BaseAPI::MakeWaypoint(phantoms[idx]);
|
return BaseAPI::MakeWaypoint(candidates[idx]);
|
||||||
});
|
});
|
||||||
return json_waypoints;
|
return json_waypoints;
|
||||||
}
|
}
|
||||||
|
|||||||
@ -26,7 +26,7 @@ class TripAPI final : public RouteAPI
|
|||||||
}
|
}
|
||||||
void MakeResponse(const std::vector<std::vector<NodeID>> &sub_trips,
|
void MakeResponse(const std::vector<std::vector<NodeID>> &sub_trips,
|
||||||
const std::vector<InternalRouteResult> &sub_routes,
|
const std::vector<InternalRouteResult> &sub_routes,
|
||||||
const std::vector<PhantomNode> &phantoms,
|
const std::vector<PhantomNodeCandidates> &candidates,
|
||||||
osrm::engine::api::ResultT &response) const
|
osrm::engine::api::ResultT &response) const
|
||||||
{
|
{
|
||||||
BOOST_ASSERT(sub_trips.size() == sub_routes.size());
|
BOOST_ASSERT(sub_trips.size() == sub_routes.size());
|
||||||
@ -34,17 +34,17 @@ class TripAPI final : public RouteAPI
|
|||||||
if (response.is<flatbuffers::FlatBufferBuilder>())
|
if (response.is<flatbuffers::FlatBufferBuilder>())
|
||||||
{
|
{
|
||||||
auto &fb_result = response.get<flatbuffers::FlatBufferBuilder>();
|
auto &fb_result = response.get<flatbuffers::FlatBufferBuilder>();
|
||||||
MakeResponse(sub_trips, sub_routes, phantoms, fb_result);
|
MakeResponse(sub_trips, sub_routes, candidates, fb_result);
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
auto &json_result = response.get<util::json::Object>();
|
auto &json_result = response.get<util::json::Object>();
|
||||||
MakeResponse(sub_trips, sub_routes, phantoms, json_result);
|
MakeResponse(sub_trips, sub_routes, candidates, json_result);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
void MakeResponse(const std::vector<std::vector<NodeID>> &sub_trips,
|
void MakeResponse(const std::vector<std::vector<NodeID>> &sub_trips,
|
||||||
const std::vector<InternalRouteResult> &sub_routes,
|
const std::vector<InternalRouteResult> &sub_routes,
|
||||||
const std::vector<PhantomNode> &phantoms,
|
const std::vector<PhantomNodeCandidates> &candidates,
|
||||||
flatbuffers::FlatBufferBuilder &fb_result) const
|
flatbuffers::FlatBufferBuilder &fb_result) const
|
||||||
{
|
{
|
||||||
auto data_timestamp = facade.GetTimestamp();
|
auto data_timestamp = facade.GetTimestamp();
|
||||||
@ -55,8 +55,8 @@ class TripAPI final : public RouteAPI
|
|||||||
}
|
}
|
||||||
|
|
||||||
auto response =
|
auto response =
|
||||||
MakeFBResponse(sub_routes, fb_result, [this, &fb_result, &sub_trips, &phantoms]() {
|
MakeFBResponse(sub_routes, fb_result, [this, &fb_result, &sub_trips, &candidates]() {
|
||||||
return MakeWaypoints(fb_result, sub_trips, phantoms);
|
return MakeWaypoints(fb_result, sub_trips, candidates);
|
||||||
});
|
});
|
||||||
|
|
||||||
if (!data_timestamp.empty())
|
if (!data_timestamp.empty())
|
||||||
@ -67,7 +67,7 @@ class TripAPI final : public RouteAPI
|
|||||||
}
|
}
|
||||||
void MakeResponse(const std::vector<std::vector<NodeID>> &sub_trips,
|
void MakeResponse(const std::vector<std::vector<NodeID>> &sub_trips,
|
||||||
const std::vector<InternalRouteResult> &sub_routes,
|
const std::vector<InternalRouteResult> &sub_routes,
|
||||||
const std::vector<PhantomNode> &phantoms,
|
const std::vector<PhantomNodeCandidates> &candidates,
|
||||||
util::json::Object &response) const
|
util::json::Object &response) const
|
||||||
{
|
{
|
||||||
auto number_of_routes = sub_trips.size();
|
auto number_of_routes = sub_trips.size();
|
||||||
@ -75,7 +75,7 @@ class TripAPI final : public RouteAPI
|
|||||||
routes.values.reserve(number_of_routes);
|
routes.values.reserve(number_of_routes);
|
||||||
for (auto index : util::irange<std::size_t>(0UL, sub_trips.size()))
|
for (auto index : util::irange<std::size_t>(0UL, sub_trips.size()))
|
||||||
{
|
{
|
||||||
auto route = MakeRoute(sub_routes[index].segment_end_coordinates,
|
auto route = MakeRoute(sub_routes[index].leg_endpoints,
|
||||||
sub_routes[index].unpacked_path_segments,
|
sub_routes[index].unpacked_path_segments,
|
||||||
sub_routes[index].source_traversed_in_reverse,
|
sub_routes[index].source_traversed_in_reverse,
|
||||||
sub_routes[index].target_traversed_in_reverse);
|
sub_routes[index].target_traversed_in_reverse);
|
||||||
@ -83,7 +83,7 @@ class TripAPI final : public RouteAPI
|
|||||||
}
|
}
|
||||||
if (!parameters.skip_waypoints)
|
if (!parameters.skip_waypoints)
|
||||||
{
|
{
|
||||||
response.values["waypoints"] = MakeWaypoints(sub_trips, phantoms);
|
response.values["waypoints"] = MakeWaypoints(sub_trips, candidates);
|
||||||
}
|
}
|
||||||
response.values["trips"] = std::move(routes);
|
response.values["trips"] = std::move(routes);
|
||||||
response.values["code"] = "Ok";
|
response.values["code"] = "Ok";
|
||||||
@ -120,7 +120,7 @@ class TripAPI final : public RouteAPI
|
|||||||
flatbuffers::Offset<flatbuffers::Vector<flatbuffers::Offset<fbresult::Waypoint>>>
|
flatbuffers::Offset<flatbuffers::Vector<flatbuffers::Offset<fbresult::Waypoint>>>
|
||||||
MakeWaypoints(flatbuffers::FlatBufferBuilder &fb_result,
|
MakeWaypoints(flatbuffers::FlatBufferBuilder &fb_result,
|
||||||
const std::vector<std::vector<NodeID>> &sub_trips,
|
const std::vector<std::vector<NodeID>> &sub_trips,
|
||||||
const std::vector<PhantomNode> &phantoms) const
|
const std::vector<PhantomNodeCandidates> &candidates) const
|
||||||
{
|
{
|
||||||
std::vector<flatbuffers::Offset<fbresult::Waypoint>> waypoints;
|
std::vector<flatbuffers::Offset<fbresult::Waypoint>> waypoints;
|
||||||
waypoints.reserve(parameters.coordinates.size());
|
waypoints.reserve(parameters.coordinates.size());
|
||||||
@ -132,7 +132,7 @@ class TripAPI final : public RouteAPI
|
|||||||
auto trip_index = input_idx_to_trip_idx[input_index];
|
auto trip_index = input_idx_to_trip_idx[input_index];
|
||||||
BOOST_ASSERT(!trip_index.NotUsed());
|
BOOST_ASSERT(!trip_index.NotUsed());
|
||||||
|
|
||||||
auto waypoint = BaseAPI::MakeWaypoint(&fb_result, phantoms[input_index]);
|
auto waypoint = BaseAPI::MakeWaypoint(&fb_result, candidates[input_index]);
|
||||||
waypoint->add_waypoint_index(trip_index.point_index);
|
waypoint->add_waypoint_index(trip_index.point_index);
|
||||||
waypoint->add_trips_index(trip_index.sub_trip_index);
|
waypoint->add_trips_index(trip_index.sub_trip_index);
|
||||||
waypoints.push_back(waypoint->Finish());
|
waypoints.push_back(waypoint->Finish());
|
||||||
@ -142,7 +142,7 @@ class TripAPI final : public RouteAPI
|
|||||||
}
|
}
|
||||||
|
|
||||||
util::json::Array MakeWaypoints(const std::vector<std::vector<NodeID>> &sub_trips,
|
util::json::Array MakeWaypoints(const std::vector<std::vector<NodeID>> &sub_trips,
|
||||||
const std::vector<PhantomNode> &phantoms) const
|
const std::vector<PhantomNodeCandidates> &candidates) const
|
||||||
{
|
{
|
||||||
util::json::Array waypoints;
|
util::json::Array waypoints;
|
||||||
waypoints.values.reserve(parameters.coordinates.size());
|
waypoints.values.reserve(parameters.coordinates.size());
|
||||||
@ -154,7 +154,7 @@ class TripAPI final : public RouteAPI
|
|||||||
auto trip_index = input_idx_to_trip_idx[input_index];
|
auto trip_index = input_idx_to_trip_idx[input_index];
|
||||||
BOOST_ASSERT(!trip_index.NotUsed());
|
BOOST_ASSERT(!trip_index.NotUsed());
|
||||||
|
|
||||||
auto waypoint = BaseAPI::MakeWaypoint(phantoms[input_index]);
|
auto waypoint = BaseAPI::MakeWaypoint(candidates[input_index]);
|
||||||
waypoint.values["trips_index"] = trip_index.sub_trip_index;
|
waypoint.values["trips_index"] = trip_index.sub_trip_index;
|
||||||
waypoint.values["waypoint_index"] = trip_index.point_index;
|
waypoint.values["waypoint_index"] = trip_index.point_index;
|
||||||
waypoints.values.push_back(std::move(waypoint));
|
waypoints.values.push_back(std::move(waypoint));
|
||||||
|
|||||||
@ -323,127 +323,41 @@ class ContiguousInternalMemoryDataFacadeBase : public BaseDataFacade
|
|||||||
|
|
||||||
std::vector<PhantomNodeWithDistance>
|
std::vector<PhantomNodeWithDistance>
|
||||||
NearestPhantomNodesInRange(const util::Coordinate input_coordinate,
|
NearestPhantomNodesInRange(const util::Coordinate input_coordinate,
|
||||||
const float max_distance,
|
const double max_distance,
|
||||||
|
const boost::optional<Bearing> bearing,
|
||||||
const Approach approach,
|
const Approach approach,
|
||||||
const bool use_all_edges) const override final
|
const bool use_all_edges) const override final
|
||||||
{
|
{
|
||||||
BOOST_ASSERT(m_geospatial_query.get());
|
BOOST_ASSERT(m_geospatial_query.get());
|
||||||
|
|
||||||
return m_geospatial_query->NearestPhantomNodesInRange(
|
return m_geospatial_query->NearestPhantomNodes(
|
||||||
input_coordinate, max_distance, approach, use_all_edges);
|
input_coordinate, approach, boost::none, max_distance, bearing, use_all_edges);
|
||||||
}
|
|
||||||
|
|
||||||
std::vector<PhantomNodeWithDistance>
|
|
||||||
NearestPhantomNodesInRange(const util::Coordinate input_coordinate,
|
|
||||||
const float max_distance,
|
|
||||||
const int bearing,
|
|
||||||
const int bearing_range,
|
|
||||||
const Approach approach,
|
|
||||||
const bool use_all_edges) const override final
|
|
||||||
{
|
|
||||||
BOOST_ASSERT(m_geospatial_query.get());
|
|
||||||
|
|
||||||
return m_geospatial_query->NearestPhantomNodesInRange(
|
|
||||||
input_coordinate, max_distance, bearing, bearing_range, approach, use_all_edges);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
std::vector<PhantomNodeWithDistance>
|
std::vector<PhantomNodeWithDistance>
|
||||||
NearestPhantomNodes(const util::Coordinate input_coordinate,
|
NearestPhantomNodes(const util::Coordinate input_coordinate,
|
||||||
const unsigned max_results,
|
const size_t max_results,
|
||||||
const Approach approach) const override final
|
const boost::optional<double> max_distance,
|
||||||
{
|
const boost::optional<Bearing> bearing,
|
||||||
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 Approach approach) const override final
|
const Approach approach) const override final
|
||||||
{
|
{
|
||||||
BOOST_ASSERT(m_geospatial_query.get());
|
BOOST_ASSERT(m_geospatial_query.get());
|
||||||
|
|
||||||
return m_geospatial_query->NearestPhantomNodes(
|
return m_geospatial_query->NearestPhantomNodes(
|
||||||
input_coordinate, max_results, max_distance, approach);
|
input_coordinate, approach, max_results, max_distance, bearing, boost::none);
|
||||||
}
|
}
|
||||||
|
|
||||||
std::vector<PhantomNodeWithDistance>
|
PhantomCandidateAlternatives
|
||||||
NearestPhantomNodes(const util::Coordinate input_coordinate,
|
NearestCandidatesWithAlternativeFromBigComponent(const util::Coordinate input_coordinate,
|
||||||
const unsigned max_results,
|
const boost::optional<double> max_distance,
|
||||||
const int bearing,
|
const boost::optional<Bearing> bearing,
|
||||||
const int bearing_range,
|
const Approach approach,
|
||||||
const Approach approach) const override final
|
const bool use_all_edges) const override final
|
||||||
{
|
{
|
||||||
BOOST_ASSERT(m_geospatial_query.get());
|
BOOST_ASSERT(m_geospatial_query.get());
|
||||||
|
|
||||||
return m_geospatial_query->NearestPhantomNodes(
|
return m_geospatial_query->NearestCandidatesWithAlternativeFromBigComponent(
|
||||||
input_coordinate, max_results, bearing, bearing_range, approach);
|
input_coordinate, approach, max_distance, bearing, use_all_edges);
|
||||||
}
|
|
||||||
|
|
||||||
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);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
std::uint32_t GetCheckSum() const override final { return m_check_sum; }
|
std::uint32_t GetCheckSum() const override final { return m_check_sum; }
|
||||||
|
|||||||
@ -35,6 +35,7 @@
|
|||||||
#include <boost/range/any_range.hpp>
|
#include <boost/range/any_range.hpp>
|
||||||
#include <cstddef>
|
#include <cstddef>
|
||||||
|
|
||||||
|
#include <engine/bearing.hpp>
|
||||||
#include <string>
|
#include <string>
|
||||||
#include <utility>
|
#include <utility>
|
||||||
#include <vector>
|
#include <vector>
|
||||||
@ -130,62 +131,24 @@ class BaseDataFacade
|
|||||||
|
|
||||||
virtual std::vector<PhantomNodeWithDistance>
|
virtual std::vector<PhantomNodeWithDistance>
|
||||||
NearestPhantomNodesInRange(const util::Coordinate input_coordinate,
|
NearestPhantomNodesInRange(const util::Coordinate input_coordinate,
|
||||||
const float max_distance,
|
const double max_distance,
|
||||||
const int bearing,
|
const boost::optional<Bearing> bearing,
|
||||||
const int bearing_range,
|
|
||||||
const Approach approach,
|
|
||||||
const bool use_all_edges) const = 0;
|
|
||||||
virtual std::vector<PhantomNodeWithDistance>
|
|
||||||
NearestPhantomNodesInRange(const util::Coordinate input_coordinate,
|
|
||||||
const float max_distance,
|
|
||||||
const Approach approach,
|
const Approach approach,
|
||||||
const bool use_all_edges) const = 0;
|
const bool use_all_edges) const = 0;
|
||||||
|
|
||||||
virtual std::vector<PhantomNodeWithDistance>
|
virtual std::vector<PhantomNodeWithDistance>
|
||||||
NearestPhantomNodes(const util::Coordinate input_coordinate,
|
NearestPhantomNodes(const util::Coordinate input_coordinate,
|
||||||
const unsigned max_results,
|
const size_t max_results,
|
||||||
const double max_distance,
|
const boost::optional<double> max_distance,
|
||||||
const int bearing,
|
const boost::optional<Bearing> bearing,
|
||||||
const int bearing_range,
|
|
||||||
const Approach approach) const = 0;
|
|
||||||
virtual std::vector<PhantomNodeWithDistance>
|
|
||||||
NearestPhantomNodes(const util::Coordinate input_coordinate,
|
|
||||||
const unsigned max_results,
|
|
||||||
const int bearing,
|
|
||||||
const int bearing_range,
|
|
||||||
const Approach approach) const = 0;
|
|
||||||
virtual std::vector<PhantomNodeWithDistance>
|
|
||||||
NearestPhantomNodes(const util::Coordinate input_coordinate,
|
|
||||||
const unsigned max_results,
|
|
||||||
const Approach approach) const = 0;
|
|
||||||
virtual std::vector<PhantomNodeWithDistance>
|
|
||||||
NearestPhantomNodes(const util::Coordinate input_coordinate,
|
|
||||||
const unsigned max_results,
|
|
||||||
const double max_distance,
|
|
||||||
const Approach approach) const = 0;
|
const Approach approach) const = 0;
|
||||||
|
|
||||||
virtual std::pair<PhantomNode, PhantomNode>
|
virtual PhantomCandidateAlternatives
|
||||||
NearestPhantomNodeWithAlternativeFromBigComponent(const util::Coordinate input_coordinate,
|
NearestCandidatesWithAlternativeFromBigComponent(const util::Coordinate input_coordinate,
|
||||||
const Approach approach,
|
const boost::optional<double> max_distance,
|
||||||
const bool use_all_edges) const = 0;
|
const boost::optional<Bearing> bearing,
|
||||||
virtual std::pair<PhantomNode, PhantomNode>
|
const Approach approach,
|
||||||
NearestPhantomNodeWithAlternativeFromBigComponent(const util::Coordinate input_coordinate,
|
const bool use_all_edges) const = 0;
|
||||||
const double max_distance,
|
|
||||||
const Approach approach,
|
|
||||||
const bool use_all_edges) const = 0;
|
|
||||||
virtual std::pair<PhantomNode, PhantomNode>
|
|
||||||
NearestPhantomNodeWithAlternativeFromBigComponent(const util::Coordinate input_coordinate,
|
|
||||||
const double max_distance,
|
|
||||||
const int bearing,
|
|
||||||
const int bearing_range,
|
|
||||||
const Approach approach,
|
|
||||||
const bool use_all_edges) const = 0;
|
|
||||||
virtual std::pair<PhantomNode, PhantomNode>
|
|
||||||
NearestPhantomNodeWithAlternativeFromBigComponent(const util::Coordinate input_coordinate,
|
|
||||||
const int bearing,
|
|
||||||
const int bearing_range,
|
|
||||||
const Approach approach,
|
|
||||||
const bool use_all_edges = false) const = 0;
|
|
||||||
|
|
||||||
virtual bool HasLaneData(const EdgeID edge_based_edge_id) const = 0;
|
virtual bool HasLaneData(const EdgeID edge_based_edge_id) const = 0;
|
||||||
virtual util::guidance::LaneTupleIdPair GetLaneData(const EdgeID edge_based_edge_id) const = 0;
|
virtual util::guidance::LaneTupleIdPair GetLaneData(const EdgeID edge_based_edge_id) const = 0;
|
||||||
|
|||||||
@ -2,6 +2,7 @@
|
|||||||
#define GEOSPATIAL_QUERY_HPP
|
#define GEOSPATIAL_QUERY_HPP
|
||||||
|
|
||||||
#include "engine/approach.hpp"
|
#include "engine/approach.hpp"
|
||||||
|
#include "engine/bearing.hpp"
|
||||||
#include "engine/phantom_node.hpp"
|
#include "engine/phantom_node.hpp"
|
||||||
#include "util/bearing.hpp"
|
#include "util/bearing.hpp"
|
||||||
#include "util/coordinate_calculation.hpp"
|
#include "util/coordinate_calculation.hpp"
|
||||||
@ -22,10 +23,10 @@ namespace osrm
|
|||||||
namespace engine
|
namespace engine
|
||||||
{
|
{
|
||||||
|
|
||||||
inline std::pair<bool, bool> boolPairAnd(const std::pair<bool, bool> &A,
|
inline std::pair<bool, bool> operator&&(const std::pair<bool, bool> &a,
|
||||||
const std::pair<bool, bool> &B)
|
const std::pair<bool, bool> &b)
|
||||||
{
|
{
|
||||||
return std::make_pair(A.first && B.first, A.second && B.second);
|
return {a.first && b.first, a.second && b.second};
|
||||||
}
|
}
|
||||||
|
|
||||||
// Implements complex queries on top of an RTree and builds PhantomNodes from it.
|
// Implements complex queries on top of an RTree and builds PhantomNodes from it.
|
||||||
@ -48,390 +49,241 @@ template <typename RTreeT, typename DataFacadeT> class GeospatialQuery
|
|||||||
return rtree.SearchInBox(bbox);
|
return rtree.SearchInBox(bbox);
|
||||||
}
|
}
|
||||||
|
|
||||||
// Returns nearest PhantomNodes in the given bearing range within max_distance.
|
// Returns max_results nearest PhantomNodes that are valid within the provided parameters.
|
||||||
// Does not filter by small/big component!
|
// Does not filter by small/big component!
|
||||||
std::vector<PhantomNodeWithDistance>
|
std::vector<PhantomNodeWithDistance>
|
||||||
NearestPhantomNodesInRange(const util::Coordinate input_coordinate,
|
NearestPhantomNodes(const util::Coordinate input_coordinate,
|
||||||
const double max_distance,
|
const Approach approach,
|
||||||
const Approach approach,
|
const boost::optional<size_t> max_results,
|
||||||
const bool use_all_edges) const
|
const boost::optional<double> max_distance,
|
||||||
|
const boost::optional<Bearing> bearing_with_range,
|
||||||
|
const boost::optional<bool> use_all_edges) const
|
||||||
{
|
{
|
||||||
auto results = rtree.Nearest(
|
auto results = rtree.Nearest(
|
||||||
input_coordinate,
|
input_coordinate,
|
||||||
[this, approach, &input_coordinate, use_all_edges](const CandidateSegment &segment) {
|
[this, approach, &input_coordinate, &bearing_with_range, &use_all_edges](
|
||||||
return boolPairAnd(
|
|
||||||
boolPairAnd(HasValidEdge(segment, use_all_edges), CheckSegmentExclude(segment)),
|
|
||||||
CheckApproach(input_coordinate, segment, approach));
|
|
||||||
},
|
|
||||||
[this, max_distance, input_coordinate](const std::size_t,
|
|
||||||
const CandidateSegment &segment) {
|
|
||||||
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](
|
|
||||||
const CandidateSegment &segment) {
|
const CandidateSegment &segment) {
|
||||||
auto use_direction =
|
auto valid = CheckSegmentExclude(segment) &&
|
||||||
boolPairAnd(CheckSegmentBearing(segment, bearing, bearing_range),
|
CheckApproach(input_coordinate, segment, approach) &&
|
||||||
boolPairAnd(HasValidEdge(segment, use_all_edges),
|
(use_all_edges ? HasValidEdge(segment, *use_all_edges)
|
||||||
CheckSegmentExclude(segment)));
|
: HasValidEdge(segment)) &&
|
||||||
use_direction =
|
(bearing_with_range ? CheckSegmentBearing(segment, *bearing_with_range)
|
||||||
boolPairAnd(use_direction, CheckApproach(input_coordinate, segment, approach));
|
: std::make_pair(true, true));
|
||||||
return use_direction;
|
return valid;
|
||||||
},
|
},
|
||||||
[this, max_distance, input_coordinate](const std::size_t,
|
[this, &max_distance, &max_results, input_coordinate](const std::size_t num_results,
|
||||||
const CandidateSegment &segment) {
|
const CandidateSegment &segment) {
|
||||||
return CheckSegmentDistance(input_coordinate, segment, max_distance);
|
return (max_results && num_results >= *max_results) ||
|
||||||
|
(max_distance &&
|
||||||
|
CheckSegmentDistance(input_coordinate, segment, *max_distance));
|
||||||
});
|
});
|
||||||
|
|
||||||
return MakePhantomNodes(input_coordinate, results);
|
return MakePhantomNodes(input_coordinate, results);
|
||||||
}
|
}
|
||||||
|
|
||||||
// Returns max_results nearest PhantomNodes in the given bearing range.
|
// Returns a list of phantom node candidates from the nearest location that are valid
|
||||||
// Does not filter by small/big component!
|
// within the provided parameters. If there is tie between equidistant locations,
|
||||||
std::vector<PhantomNodeWithDistance>
|
// we only pick candidates from one location.
|
||||||
NearestPhantomNodes(const util::Coordinate input_coordinate,
|
// If candidates do not include a node from a big component, an alternative list of candidates
|
||||||
const unsigned max_results,
|
// from the nearest location which has nodes from a big component is returned.
|
||||||
const int bearing,
|
PhantomCandidateAlternatives NearestCandidatesWithAlternativeFromBigComponent(
|
||||||
const int bearing_range,
|
const util::Coordinate input_coordinate,
|
||||||
const Approach approach) const
|
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(
|
bool has_nearest = false;
|
||||||
input_coordinate,
|
|
||||||
[this, approach, &input_coordinate, bearing, bearing_range](
|
|
||||||
const CandidateSegment &segment) {
|
|
||||||
auto use_direction =
|
|
||||||
boolPairAnd(CheckSegmentBearing(segment, bearing, bearing_range),
|
|
||||||
boolPairAnd(HasValidEdge(segment), CheckSegmentExclude(segment)));
|
|
||||||
return boolPairAnd(use_direction,
|
|
||||||
CheckApproach(input_coordinate, segment, approach));
|
|
||||||
},
|
|
||||||
[max_results](const std::size_t num_results, const CandidateSegment &) {
|
|
||||||
return num_results >= max_results;
|
|
||||||
});
|
|
||||||
|
|
||||||
return MakePhantomNodes(input_coordinate, results);
|
|
||||||
}
|
|
||||||
|
|
||||||
// Returns max_results nearest PhantomNodes in the given bearing range within the maximum
|
|
||||||
// distance.
|
|
||||||
// Does not filter by small/big component!
|
|
||||||
std::vector<PhantomNodeWithDistance>
|
|
||||||
NearestPhantomNodes(const util::Coordinate input_coordinate,
|
|
||||||
const unsigned max_results,
|
|
||||||
const double max_distance,
|
|
||||||
const int bearing,
|
|
||||||
const int bearing_range,
|
|
||||||
const Approach approach) const
|
|
||||||
{
|
|
||||||
auto results = rtree.Nearest(
|
|
||||||
input_coordinate,
|
|
||||||
[this, approach, &input_coordinate, bearing, bearing_range](
|
|
||||||
const CandidateSegment &segment) {
|
|
||||||
auto use_direction =
|
|
||||||
boolPairAnd(CheckSegmentBearing(segment, bearing, bearing_range),
|
|
||||||
boolPairAnd(HasValidEdge(segment), CheckSegmentExclude(segment)));
|
|
||||||
return boolPairAnd(use_direction,
|
|
||||||
CheckApproach(input_coordinate, segment, approach));
|
|
||||||
},
|
|
||||||
[this, max_distance, max_results, input_coordinate](const std::size_t num_results,
|
|
||||||
const CandidateSegment &segment) {
|
|
||||||
return num_results >= max_results ||
|
|
||||||
CheckSegmentDistance(input_coordinate, segment, max_distance);
|
|
||||||
});
|
|
||||||
|
|
||||||
return MakePhantomNodes(input_coordinate, results);
|
|
||||||
}
|
|
||||||
|
|
||||||
// Returns max_results nearest PhantomNodes.
|
|
||||||
// Does not filter by small/big component!
|
|
||||||
std::vector<PhantomNodeWithDistance>
|
|
||||||
NearestPhantomNodes(const util::Coordinate input_coordinate,
|
|
||||||
const unsigned max_results,
|
|
||||||
const Approach approach) const
|
|
||||||
{
|
|
||||||
auto results = rtree.Nearest(
|
|
||||||
input_coordinate,
|
|
||||||
[this, approach, &input_coordinate](const CandidateSegment &segment) {
|
|
||||||
return boolPairAnd(boolPairAnd(HasValidEdge(segment), CheckSegmentExclude(segment)),
|
|
||||||
CheckApproach(input_coordinate, segment, approach));
|
|
||||||
},
|
|
||||||
[max_results](const std::size_t num_results, const CandidateSegment &) {
|
|
||||||
return num_results >= max_results;
|
|
||||||
});
|
|
||||||
|
|
||||||
return MakePhantomNodes(input_coordinate, results);
|
|
||||||
}
|
|
||||||
|
|
||||||
// Returns max_results nearest PhantomNodes in the given max distance.
|
|
||||||
// Does not filter by small/big component!
|
|
||||||
std::vector<PhantomNodeWithDistance>
|
|
||||||
NearestPhantomNodes(const util::Coordinate input_coordinate,
|
|
||||||
const unsigned max_results,
|
|
||||||
const double max_distance,
|
|
||||||
const Approach approach) const
|
|
||||||
{
|
|
||||||
auto results = rtree.Nearest(
|
|
||||||
input_coordinate,
|
|
||||||
[this, approach, &input_coordinate](const CandidateSegment &segment) {
|
|
||||||
return boolPairAnd(boolPairAnd(HasValidEdge(segment), CheckSegmentExclude(segment)),
|
|
||||||
CheckApproach(input_coordinate, segment, approach));
|
|
||||||
},
|
|
||||||
[this, max_distance, max_results, input_coordinate](const std::size_t num_results,
|
|
||||||
const CandidateSegment &segment) {
|
|
||||||
return num_results >= max_results ||
|
|
||||||
CheckSegmentDistance(input_coordinate, segment, max_distance);
|
|
||||||
});
|
|
||||||
|
|
||||||
return MakePhantomNodes(input_coordinate, results);
|
|
||||||
}
|
|
||||||
|
|
||||||
// Returns the nearest phantom node. If this phantom node is not from a big component
|
|
||||||
// a second phantom node is return that is the nearest coordinate in a big component.
|
|
||||||
std::pair<PhantomNode, PhantomNode>
|
|
||||||
NearestPhantomNodeWithAlternativeFromBigComponent(const util::Coordinate input_coordinate,
|
|
||||||
const double max_distance,
|
|
||||||
const Approach approach,
|
|
||||||
const bool use_all_edges) const
|
|
||||||
{
|
|
||||||
bool has_small_component = false;
|
|
||||||
bool has_big_component = false;
|
bool has_big_component = false;
|
||||||
|
Coordinate big_component_coord;
|
||||||
|
double big_component_distance = std::numeric_limits<double>::max();
|
||||||
|
Coordinate nearest_coord;
|
||||||
auto results = rtree.Nearest(
|
auto results = rtree.Nearest(
|
||||||
input_coordinate,
|
input_coordinate,
|
||||||
[this,
|
[this,
|
||||||
approach,
|
approach,
|
||||||
&input_coordinate,
|
&input_coordinate,
|
||||||
|
&has_nearest,
|
||||||
&has_big_component,
|
&has_big_component,
|
||||||
&has_small_component,
|
&nearest_coord,
|
||||||
&use_all_edges](const CandidateSegment &segment) {
|
&big_component_coord,
|
||||||
auto use_segment =
|
&big_component_distance,
|
||||||
(!has_small_component || (!has_big_component && !IsTinyComponent(segment)));
|
&use_all_edges,
|
||||||
auto use_directions = std::make_pair(use_segment, use_segment);
|
&bearing_with_range](const CandidateSegment &segment) {
|
||||||
const auto valid_edges = HasValidEdge(segment, use_all_edges);
|
auto is_big_component = !IsTinyComponent(segment);
|
||||||
const auto admissible_segments = CheckSegmentExclude(segment);
|
auto not_nearest =
|
||||||
use_directions = boolPairAnd(use_directions, admissible_segments);
|
has_nearest && segment.fixed_projected_coordinate != nearest_coord;
|
||||||
use_directions = boolPairAnd(use_directions, valid_edges);
|
auto not_big =
|
||||||
use_directions =
|
has_big_component && segment.fixed_projected_coordinate != big_component_coord;
|
||||||
boolPairAnd(use_directions, CheckApproach(input_coordinate, segment, approach));
|
|
||||||
|
|
||||||
if (use_directions.first || use_directions.second)
|
/**
|
||||||
|
*
|
||||||
|
* Two reasons why we don't want this candidate:
|
||||||
|
* 1. A non-big component candidate that is not at the nearest location
|
||||||
|
* 2. A big component candidate that is not at the big location.
|
||||||
|
*
|
||||||
|
* It's possible that 1. could end up having the same location as the nearest big
|
||||||
|
* component node if we have yet to see one. However, we don't know this and it
|
||||||
|
* could lead to buffering large numbers of candidates before finding the big
|
||||||
|
* component location.
|
||||||
|
* By filtering out 1. nodes, this does mean that the alternative list of
|
||||||
|
* candidates will not have non-big component candidates. Given the alternative
|
||||||
|
* list of big component candidates is meant as a backup choice, this seems
|
||||||
|
* reasonable.
|
||||||
|
*/
|
||||||
|
if ((!is_big_component && not_nearest) || (is_big_component && not_big))
|
||||||
{
|
{
|
||||||
has_big_component = has_big_component || !IsTinyComponent(segment);
|
return std::make_pair(false, false);
|
||||||
has_small_component = has_small_component || IsTinyComponent(segment);
|
|
||||||
}
|
}
|
||||||
|
auto use_candidate =
|
||||||
|
CheckSegmentExclude(segment) &&
|
||||||
|
CheckApproach(input_coordinate, segment, approach) &&
|
||||||
|
(use_all_edges ? HasValidEdge(segment, *use_all_edges)
|
||||||
|
: HasValidEdge(segment)) &&
|
||||||
|
(bearing_with_range ? CheckSegmentBearing(segment, *bearing_with_range)
|
||||||
|
: std::make_pair(true, true));
|
||||||
|
|
||||||
return use_directions;
|
if (use_candidate.first || use_candidate.second)
|
||||||
},
|
|
||||||
[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)
|
|
||||||
{
|
{
|
||||||
has_big_component = has_big_component || !IsTinyComponent(segment);
|
if (!has_nearest)
|
||||||
has_small_component = has_small_component || IsTinyComponent(segment);
|
|
||||||
}
|
|
||||||
|
|
||||||
return use_directions;
|
|
||||||
},
|
|
||||||
[&has_big_component](const std::size_t num_results, const CandidateSegment &) {
|
|
||||||
return num_results > 0 && has_big_component;
|
|
||||||
});
|
|
||||||
|
|
||||||
if (results.size() == 0)
|
|
||||||
{
|
|
||||||
return std::make_pair(PhantomNode{}, PhantomNode{});
|
|
||||||
}
|
|
||||||
|
|
||||||
BOOST_ASSERT(results.size() == 1 || results.size() == 2);
|
|
||||||
return std::make_pair(MakePhantomNode(input_coordinate, results.front()).phantom_node,
|
|
||||||
MakePhantomNode(input_coordinate, results.back()).phantom_node);
|
|
||||||
}
|
|
||||||
|
|
||||||
// Returns the nearest phantom node. If this phantom node is not from a big component
|
|
||||||
// a second phantom node is return that is the nearest coordinate in a big component.
|
|
||||||
std::pair<PhantomNode, PhantomNode>
|
|
||||||
NearestPhantomNodeWithAlternativeFromBigComponent(const util::Coordinate input_coordinate,
|
|
||||||
const int bearing,
|
|
||||||
const int bearing_range,
|
|
||||||
const Approach approach,
|
|
||||||
const bool use_all_edges) const
|
|
||||||
{
|
|
||||||
bool has_small_component = false;
|
|
||||||
bool has_big_component = false;
|
|
||||||
auto results = rtree.Nearest(
|
|
||||||
input_coordinate,
|
|
||||||
[this,
|
|
||||||
approach,
|
|
||||||
&input_coordinate,
|
|
||||||
bearing,
|
|
||||||
bearing_range,
|
|
||||||
&has_big_component,
|
|
||||||
&has_small_component,
|
|
||||||
&use_all_edges](const CandidateSegment &segment) {
|
|
||||||
auto use_segment =
|
|
||||||
(!has_small_component || (!has_big_component && !IsTinyComponent(segment)));
|
|
||||||
auto use_directions = std::make_pair(use_segment, use_segment);
|
|
||||||
const auto admissible_segments = CheckSegmentExclude(segment);
|
|
||||||
|
|
||||||
if (use_segment)
|
|
||||||
{
|
|
||||||
use_directions =
|
|
||||||
boolPairAnd(CheckSegmentBearing(segment, bearing, bearing_range),
|
|
||||||
HasValidEdge(segment, use_all_edges));
|
|
||||||
use_directions = boolPairAnd(use_directions, admissible_segments);
|
|
||||||
use_directions = boolPairAnd(
|
|
||||||
use_directions, CheckApproach(input_coordinate, segment, approach));
|
|
||||||
|
|
||||||
if (use_directions.first || use_directions.second)
|
|
||||||
{
|
{
|
||||||
has_big_component = has_big_component || !IsTinyComponent(segment);
|
has_nearest = true;
|
||||||
has_small_component = has_small_component || IsTinyComponent(segment);
|
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 &) {
|
[this, &has_big_component, &max_distance, input_coordinate, &big_component_distance](
|
||||||
return num_results > 0 && has_big_component;
|
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 MakeAlternativeBigCandidates(input_coordinate, nearest_coord, results);
|
||||||
{
|
|
||||||
return std::make_pair(PhantomNode{}, PhantomNode{});
|
|
||||||
}
|
|
||||||
|
|
||||||
BOOST_ASSERT(results.size() > 0);
|
|
||||||
return std::make_pair(MakePhantomNode(input_coordinate, results.front()).phantom_node,
|
|
||||||
MakePhantomNode(input_coordinate, results.back()).phantom_node);
|
|
||||||
}
|
|
||||||
|
|
||||||
// Returns the nearest phantom node. If this phantom node is not from a big component
|
|
||||||
// a second phantom node is return that is the nearest coordinate in a big component.
|
|
||||||
std::pair<PhantomNode, PhantomNode>
|
|
||||||
NearestPhantomNodeWithAlternativeFromBigComponent(const util::Coordinate input_coordinate,
|
|
||||||
const double max_distance,
|
|
||||||
const int bearing,
|
|
||||||
const int bearing_range,
|
|
||||||
const Approach approach,
|
|
||||||
const bool use_all_edges) const
|
|
||||||
{
|
|
||||||
bool has_small_component = false;
|
|
||||||
bool has_big_component = false;
|
|
||||||
auto results = rtree.Nearest(
|
|
||||||
input_coordinate,
|
|
||||||
[this,
|
|
||||||
approach,
|
|
||||||
&input_coordinate,
|
|
||||||
bearing,
|
|
||||||
bearing_range,
|
|
||||||
&has_big_component,
|
|
||||||
&has_small_component,
|
|
||||||
&use_all_edges](const CandidateSegment &segment) {
|
|
||||||
auto use_segment =
|
|
||||||
(!has_small_component || (!has_big_component && !IsTinyComponent(segment)));
|
|
||||||
auto use_directions = std::make_pair(use_segment, use_segment);
|
|
||||||
const auto admissible_segments = CheckSegmentExclude(segment);
|
|
||||||
|
|
||||||
if (use_segment)
|
|
||||||
{
|
|
||||||
use_directions =
|
|
||||||
boolPairAnd(CheckSegmentBearing(segment, bearing, bearing_range),
|
|
||||||
HasValidEdge(segment, use_all_edges));
|
|
||||||
use_directions = boolPairAnd(use_directions, admissible_segments);
|
|
||||||
use_directions = boolPairAnd(
|
|
||||||
use_directions, CheckApproach(input_coordinate, segment, approach));
|
|
||||||
|
|
||||||
if (use_directions.first || use_directions.second)
|
|
||||||
{
|
|
||||||
has_big_component = has_big_component || !IsTinyComponent(segment);
|
|
||||||
has_small_component = has_small_component || IsTinyComponent(segment);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
return use_directions;
|
|
||||||
},
|
|
||||||
[this, &has_big_component, max_distance, input_coordinate](
|
|
||||||
const std::size_t num_results, const CandidateSegment &segment) {
|
|
||||||
return (num_results > 0 && has_big_component) ||
|
|
||||||
CheckSegmentDistance(input_coordinate, segment, max_distance);
|
|
||||||
});
|
|
||||||
|
|
||||||
if (results.size() == 0)
|
|
||||||
{
|
|
||||||
return std::make_pair(PhantomNode{}, PhantomNode{});
|
|
||||||
}
|
|
||||||
|
|
||||||
BOOST_ASSERT(results.size() > 0);
|
|
||||||
return std::make_pair(MakePhantomNode(input_coordinate, results.front()).phantom_node,
|
|
||||||
MakePhantomNode(input_coordinate, results.back()).phantom_node);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
private:
|
private:
|
||||||
|
PhantomCandidateAlternatives
|
||||||
|
MakeAlternativeBigCandidates(const util::Coordinate input_coordinate,
|
||||||
|
const Coordinate nearest_coord,
|
||||||
|
const std::vector<CandidateSegment> &results) const
|
||||||
|
{
|
||||||
|
if (results.size() == 0)
|
||||||
|
{
|
||||||
|
return std::make_pair(PhantomNodeCandidates{}, PhantomNodeCandidates{});
|
||||||
|
}
|
||||||
|
|
||||||
|
PhantomNodeCandidates nearest_phantoms;
|
||||||
|
PhantomNodeCandidates big_component_phantoms;
|
||||||
|
|
||||||
|
const auto add_to_candidates = [this, &input_coordinate](PhantomNodeCandidates &candidates,
|
||||||
|
const EdgeData data) {
|
||||||
|
auto candidate_it =
|
||||||
|
std::find_if(candidates.begin(), candidates.end(), [&](const PhantomNode &node) {
|
||||||
|
return data.forward_segment_id.id == node.forward_segment_id.id &&
|
||||||
|
data.reverse_segment_id.id == node.reverse_segment_id.id;
|
||||||
|
});
|
||||||
|
if (candidate_it == candidates.end())
|
||||||
|
{
|
||||||
|
// First candidate from this segment
|
||||||
|
candidates.push_back(MakePhantomNode(input_coordinate, data).phantom_node);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
/**
|
||||||
|
* Second candidate from this segment (there can be at most two).
|
||||||
|
* We're snapping at the connection between two edges e1,e2 of the segment.
|
||||||
|
*
|
||||||
|
* | e1 | e2 |
|
||||||
|
* | --- f1 --> | --- f2 --> |
|
||||||
|
* | <-- r1 --- | <-- r2 --- |
|
||||||
|
*
|
||||||
|
* Most of the routing algorithms only support one candidate from each segment.
|
||||||
|
* Therefore, we have to choose between e1 and e2.
|
||||||
|
*
|
||||||
|
* It makes sense to pick one edge over another if that edge offers more
|
||||||
|
* opportunities to act as a source or target for a route.
|
||||||
|
*
|
||||||
|
* For consistency, we use the following logic:
|
||||||
|
* "Pick e1 unless it makes sense to choose e2"
|
||||||
|
*
|
||||||
|
* Representing edge enabled as a truth table:
|
||||||
|
* f1 | r1 | f2 | r2 | selected
|
||||||
|
* ____________________________
|
||||||
|
* t | t | t | t | e1
|
||||||
|
* t | t | t | f | e1
|
||||||
|
* t | t | f | t | e1
|
||||||
|
* t | f | t | t | e2
|
||||||
|
* t | f | t | f | e1
|
||||||
|
* t | f | f | t | e1
|
||||||
|
* f | t | t | t | e2
|
||||||
|
* f | t | t | f | e1
|
||||||
|
* f | t | f | t | e1
|
||||||
|
*
|
||||||
|
* The other rows in truth table don't appear as we discard an edge if both
|
||||||
|
* forward and reverse are disabled.
|
||||||
|
*
|
||||||
|
**/
|
||||||
|
if (candidate_it->fwd_segment_position < data.fwd_segment_position)
|
||||||
|
{
|
||||||
|
if (data.forward_segment_id.enabled && data.reverse_segment_id.enabled &&
|
||||||
|
!(candidate_it->forward_segment_id.enabled &&
|
||||||
|
candidate_it->reverse_segment_id.enabled))
|
||||||
|
{
|
||||||
|
*candidate_it = MakePhantomNode(input_coordinate, data).phantom_node;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
if (!candidate_it->forward_segment_id.enabled ||
|
||||||
|
!candidate_it->reverse_segment_id.enabled ||
|
||||||
|
(data.forward_segment_id.enabled && data.reverse_segment_id.enabled))
|
||||||
|
{
|
||||||
|
*candidate_it = MakePhantomNode(input_coordinate, data).phantom_node;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
std::for_each(results.begin(), results.end(), [&](const CandidateSegment &segment) {
|
||||||
|
if (segment.fixed_projected_coordinate == nearest_coord)
|
||||||
|
{
|
||||||
|
add_to_candidates(nearest_phantoms, segment.data);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
// Can only be from a big component for the alternative candidates
|
||||||
|
add_to_candidates(big_component_phantoms, segment.data);
|
||||||
|
}
|
||||||
|
});
|
||||||
|
return std::make_pair(std::move(nearest_phantoms), std::move(big_component_phantoms));
|
||||||
|
}
|
||||||
|
|
||||||
std::vector<PhantomNodeWithDistance>
|
std::vector<PhantomNodeWithDistance>
|
||||||
MakePhantomNodes(const util::Coordinate input_coordinate,
|
MakePhantomNodes(const util::Coordinate input_coordinate,
|
||||||
const std::vector<EdgeData> &results) const
|
const std::vector<CandidateSegment> &results) const
|
||||||
{
|
{
|
||||||
std::vector<PhantomNodeWithDistance> distance_and_phantoms(results.size());
|
std::vector<PhantomNodeWithDistance> distance_and_phantoms(results.size());
|
||||||
std::transform(results.begin(),
|
std::transform(results.begin(),
|
||||||
results.end(),
|
results.end(),
|
||||||
distance_and_phantoms.begin(),
|
distance_and_phantoms.begin(),
|
||||||
[this, &input_coordinate](const EdgeData &data) {
|
[this, &input_coordinate](const CandidateSegment &segment) {
|
||||||
return MakePhantomNode(input_coordinate, data);
|
return MakePhantomNode(input_coordinate, segment.data);
|
||||||
});
|
});
|
||||||
return distance_and_phantoms;
|
return distance_and_phantoms;
|
||||||
}
|
}
|
||||||
@ -580,9 +432,8 @@ template <typename RTreeT, typename DataFacadeT> class GeospatialQuery
|
|||||||
return transformed;
|
return transformed;
|
||||||
}
|
}
|
||||||
|
|
||||||
bool CheckSegmentDistance(const Coordinate input_coordinate,
|
double GetSegmentDistance(const Coordinate input_coordinate,
|
||||||
const CandidateSegment &segment,
|
const CandidateSegment &segment) const
|
||||||
const double max_distance) const
|
|
||||||
{
|
{
|
||||||
BOOST_ASSERT(segment.data.forward_segment_id.id != SPECIAL_SEGMENTID ||
|
BOOST_ASSERT(segment.data.forward_segment_id.id != SPECIAL_SEGMENTID ||
|
||||||
!segment.data.forward_segment_id.enabled);
|
!segment.data.forward_segment_id.enabled);
|
||||||
@ -593,7 +444,14 @@ template <typename RTreeT, typename DataFacadeT> class GeospatialQuery
|
|||||||
util::web_mercator::toWGS84(segment.fixed_projected_coordinate);
|
util::web_mercator::toWGS84(segment.fixed_projected_coordinate);
|
||||||
|
|
||||||
return util::coordinate_calculation::greatCircleDistance(input_coordinate,
|
return util::coordinate_calculation::greatCircleDistance(input_coordinate,
|
||||||
wsg84_coordinate) > max_distance;
|
wsg84_coordinate);
|
||||||
|
}
|
||||||
|
|
||||||
|
bool CheckSegmentDistance(const Coordinate input_coordinate,
|
||||||
|
const CandidateSegment &segment,
|
||||||
|
const double max_distance) const
|
||||||
|
{
|
||||||
|
return GetSegmentDistance(input_coordinate, segment) > max_distance;
|
||||||
}
|
}
|
||||||
|
|
||||||
std::pair<bool, bool> CheckSegmentExclude(const CandidateSegment &segment) const
|
std::pair<bool, bool> CheckSegmentExclude(const CandidateSegment &segment) const
|
||||||
@ -616,8 +474,7 @@ template <typename RTreeT, typename DataFacadeT> class GeospatialQuery
|
|||||||
}
|
}
|
||||||
|
|
||||||
std::pair<bool, bool> CheckSegmentBearing(const CandidateSegment &segment,
|
std::pair<bool, bool> CheckSegmentBearing(const CandidateSegment &segment,
|
||||||
const int filter_bearing,
|
const Bearing filter_bearing) const
|
||||||
const int filter_bearing_range) const
|
|
||||||
{
|
{
|
||||||
BOOST_ASSERT(segment.data.forward_segment_id.id != SPECIAL_SEGMENTID ||
|
BOOST_ASSERT(segment.data.forward_segment_id.id != SPECIAL_SEGMENTID ||
|
||||||
!segment.data.forward_segment_id.enabled);
|
!segment.data.forward_segment_id.enabled);
|
||||||
@ -633,11 +490,11 @@ template <typename RTreeT, typename DataFacadeT> class GeospatialQuery
|
|||||||
|
|
||||||
const bool forward_bearing_valid =
|
const bool forward_bearing_valid =
|
||||||
util::bearing::CheckInBounds(
|
util::bearing::CheckInBounds(
|
||||||
std::round(forward_edge_bearing), filter_bearing, filter_bearing_range) &&
|
std::round(forward_edge_bearing), filter_bearing.bearing, filter_bearing.range) &&
|
||||||
segment.data.forward_segment_id.enabled;
|
segment.data.forward_segment_id.enabled;
|
||||||
const bool backward_bearing_valid =
|
const bool backward_bearing_valid =
|
||||||
util::bearing::CheckInBounds(
|
util::bearing::CheckInBounds(
|
||||||
std::round(backward_edge_bearing), filter_bearing, filter_bearing_range) &&
|
std::round(backward_edge_bearing), filter_bearing.bearing, filter_bearing.range) &&
|
||||||
segment.data.reverse_segment_id.enabled;
|
segment.data.reverse_segment_id.enabled;
|
||||||
return std::make_pair(forward_bearing_valid, backward_bearing_valid);
|
return std::make_pair(forward_bearing_valid, backward_bearing_valid);
|
||||||
}
|
}
|
||||||
@ -645,7 +502,7 @@ template <typename RTreeT, typename DataFacadeT> class GeospatialQuery
|
|||||||
/**
|
/**
|
||||||
* Checks to see if the edge weights are valid. We might have an edge,
|
* Checks to see if the edge weights are valid. We might have an edge,
|
||||||
* but a traffic update might set the speed to 0 (weight == INVALID_SEGMENT_WEIGHT).
|
* but a traffic update might set the speed to 0 (weight == INVALID_SEGMENT_WEIGHT).
|
||||||
* which means that this edge is not currently traversible. If this is the case,
|
* which means that this edge is not currently traversable. If this is the case,
|
||||||
* then we shouldn't snap to this edge.
|
* then we shouldn't snap to this edge.
|
||||||
*/
|
*/
|
||||||
std::pair<bool, bool> HasValidEdge(const CandidateSegment &segment,
|
std::pair<bool, bool> HasValidEdge(const CandidateSegment &segment,
|
||||||
@ -682,7 +539,7 @@ template <typename RTreeT, typename DataFacadeT> class GeospatialQuery
|
|||||||
bool IsTinyComponent(const CandidateSegment &segment) const
|
bool IsTinyComponent(const CandidateSegment &segment) const
|
||||||
{
|
{
|
||||||
const auto &data = segment.data;
|
const auto &data = segment.data;
|
||||||
BOOST_ASSERT(data.forward_segment_id.enabled);
|
BOOST_ASSERT(data.forward_segment_id.enabled || data.reverse_segment_id.enabled);
|
||||||
BOOST_ASSERT(data.forward_segment_id.id != SPECIAL_NODEID);
|
BOOST_ASSERT(data.forward_segment_id.id != SPECIAL_NODEID);
|
||||||
return datafacade.GetComponentID(data.forward_segment_id.id).is_tiny;
|
return datafacade.GetComponentID(data.forward_segment_id.id).is_tiny;
|
||||||
}
|
}
|
||||||
|
|||||||
@ -47,8 +47,9 @@ namespace datafacade
|
|||||||
class BaseDataFacade;
|
class BaseDataFacade;
|
||||||
}
|
}
|
||||||
|
|
||||||
// Is returned as a temporary identifier for snapped coodinates
|
// SegmentHint represents an individual segment position that could be used
|
||||||
struct Hint
|
// as the waypoint for a given input location
|
||||||
|
struct SegmentHint
|
||||||
{
|
{
|
||||||
PhantomNode phantom;
|
PhantomNode phantom;
|
||||||
std::uint32_t data_checksum;
|
std::uint32_t data_checksum;
|
||||||
@ -57,16 +58,31 @@ struct Hint
|
|||||||
const datafacade::BaseDataFacade &facade) const;
|
const datafacade::BaseDataFacade &facade) const;
|
||||||
|
|
||||||
std::string ToBase64() const;
|
std::string ToBase64() const;
|
||||||
static Hint FromBase64(const std::string &base64Hint);
|
static SegmentHint FromBase64(const std::string &base64Hint);
|
||||||
|
|
||||||
friend bool operator==(const Hint &, const Hint &);
|
friend bool operator==(const SegmentHint &, const SegmentHint &);
|
||||||
friend std::ostream &operator<<(std::ostream &, const Hint &);
|
friend bool operator!=(const SegmentHint &, const SegmentHint &);
|
||||||
|
friend std::ostream &operator<<(std::ostream &, const SegmentHint &);
|
||||||
};
|
};
|
||||||
|
|
||||||
static_assert(sizeof(Hint) == 80 + 4, "Hint is bigger than expected");
|
// Hint represents the suggested segment positions that could be used
|
||||||
constexpr std::size_t ENCODED_HINT_SIZE = 112;
|
// as the waypoint for a given input location
|
||||||
static_assert(ENCODED_HINT_SIZE / 4 * 3 >= sizeof(Hint),
|
struct Hint
|
||||||
"ENCODED_HINT_SIZE does not match size of Hint");
|
{
|
||||||
|
std::vector<SegmentHint> segment_hints;
|
||||||
|
|
||||||
|
bool IsValid(const util::Coordinate new_input_coordinates,
|
||||||
|
const datafacade::BaseDataFacade &facade) const;
|
||||||
|
|
||||||
|
std::string ToBase64() const;
|
||||||
|
static Hint FromBase64(const std::string &base64Hint);
|
||||||
|
};
|
||||||
|
|
||||||
|
static_assert(sizeof(SegmentHint) == 80 + 4, "Hint is bigger than expected");
|
||||||
|
constexpr std::size_t ENCODED_SEGMENT_HINT_SIZE = 112;
|
||||||
|
static_assert(ENCODED_SEGMENT_HINT_SIZE / 4 * 3 >= sizeof(SegmentHint),
|
||||||
|
"ENCODED_SEGMENT_HINT_SIZE does not match size of SegmentHint");
|
||||||
|
|
||||||
} // namespace engine
|
} // namespace engine
|
||||||
} // namespace osrm
|
} // namespace osrm
|
||||||
|
|
||||||
|
|||||||
@ -50,7 +50,7 @@ struct PathData
|
|||||||
struct InternalRouteResult
|
struct InternalRouteResult
|
||||||
{
|
{
|
||||||
std::vector<std::vector<PathData>> unpacked_path_segments;
|
std::vector<std::vector<PathData>> unpacked_path_segments;
|
||||||
std::vector<PhantomNodes> segment_end_coordinates;
|
std::vector<PhantomEndpoints> leg_endpoints;
|
||||||
std::vector<bool> source_traversed_in_reverse;
|
std::vector<bool> source_traversed_in_reverse;
|
||||||
std::vector<bool> target_traversed_in_reverse;
|
std::vector<bool> target_traversed_in_reverse;
|
||||||
EdgeWeight shortest_path_weight = INVALID_EDGE_WEIGHT;
|
EdgeWeight shortest_path_weight = INVALID_EDGE_WEIGHT;
|
||||||
@ -96,7 +96,7 @@ inline InternalRouteResult CollapseInternalRouteResult(const InternalRouteResult
|
|||||||
if (leggy_result.unpacked_path_segments.size() == 1)
|
if (leggy_result.unpacked_path_segments.size() == 1)
|
||||||
return leggy_result;
|
return leggy_result;
|
||||||
|
|
||||||
BOOST_ASSERT(leggy_result.segment_end_coordinates.size() > 1);
|
BOOST_ASSERT(leggy_result.leg_endpoints.size() > 1);
|
||||||
|
|
||||||
InternalRouteResult collapsed;
|
InternalRouteResult collapsed;
|
||||||
collapsed.shortest_path_weight = leggy_result.shortest_path_weight;
|
collapsed.shortest_path_weight = leggy_result.shortest_path_weight;
|
||||||
@ -107,7 +107,7 @@ inline InternalRouteResult CollapseInternalRouteResult(const InternalRouteResult
|
|||||||
// start another leg vector
|
// start another leg vector
|
||||||
collapsed.unpacked_path_segments.push_back(leggy_result.unpacked_path_segments[i]);
|
collapsed.unpacked_path_segments.push_back(leggy_result.unpacked_path_segments[i]);
|
||||||
// save new phantom node pair
|
// save new phantom node pair
|
||||||
collapsed.segment_end_coordinates.push_back(leggy_result.segment_end_coordinates[i]);
|
collapsed.leg_endpoints.push_back(leggy_result.leg_endpoints[i]);
|
||||||
// save data about phantom nodes
|
// save data about phantom nodes
|
||||||
collapsed.source_traversed_in_reverse.push_back(
|
collapsed.source_traversed_in_reverse.push_back(
|
||||||
leggy_result.source_traversed_in_reverse[i]);
|
leggy_result.source_traversed_in_reverse[i]);
|
||||||
@ -119,9 +119,9 @@ inline InternalRouteResult CollapseInternalRouteResult(const InternalRouteResult
|
|||||||
{
|
{
|
||||||
BOOST_ASSERT(!collapsed.unpacked_path_segments.empty());
|
BOOST_ASSERT(!collapsed.unpacked_path_segments.empty());
|
||||||
auto &last_segment = collapsed.unpacked_path_segments.back();
|
auto &last_segment = collapsed.unpacked_path_segments.back();
|
||||||
BOOST_ASSERT(!collapsed.segment_end_coordinates.empty());
|
BOOST_ASSERT(!collapsed.leg_endpoints.empty());
|
||||||
collapsed.segment_end_coordinates.back().target_phantom =
|
collapsed.leg_endpoints.back().target_phantom =
|
||||||
leggy_result.segment_end_coordinates[i].target_phantom;
|
leggy_result.leg_endpoints[i].target_phantom;
|
||||||
collapsed.target_traversed_in_reverse.back() =
|
collapsed.target_traversed_in_reverse.back() =
|
||||||
leggy_result.target_traversed_in_reverse[i];
|
leggy_result.target_traversed_in_reverse[i];
|
||||||
// copy path segments into current leg
|
// copy path segments into current leg
|
||||||
@ -138,19 +138,18 @@ inline InternalRouteResult CollapseInternalRouteResult(const InternalRouteResult
|
|||||||
last_segment[old_size].weight_until_turn +=
|
last_segment[old_size].weight_until_turn +=
|
||||||
|
|
||||||
leggy_result.source_traversed_in_reverse[i]
|
leggy_result.source_traversed_in_reverse[i]
|
||||||
? leggy_result.segment_end_coordinates[i].source_phantom.reverse_weight
|
? leggy_result.leg_endpoints[i].source_phantom.reverse_weight
|
||||||
: leggy_result.segment_end_coordinates[i].source_phantom.forward_weight;
|
: leggy_result.leg_endpoints[i].source_phantom.forward_weight;
|
||||||
|
|
||||||
last_segment[old_size].duration_until_turn +=
|
last_segment[old_size].duration_until_turn +=
|
||||||
leggy_result.source_traversed_in_reverse[i]
|
leggy_result.source_traversed_in_reverse[i]
|
||||||
? leggy_result.segment_end_coordinates[i].source_phantom.reverse_duration
|
? leggy_result.leg_endpoints[i].source_phantom.reverse_duration
|
||||||
: leggy_result.segment_end_coordinates[i].source_phantom.forward_duration;
|
: leggy_result.leg_endpoints[i].source_phantom.forward_duration;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
BOOST_ASSERT(collapsed.segment_end_coordinates.size() ==
|
BOOST_ASSERT(collapsed.leg_endpoints.size() == collapsed.unpacked_path_segments.size());
|
||||||
collapsed.unpacked_path_segments.size());
|
|
||||||
return collapsed;
|
return collapsed;
|
||||||
}
|
}
|
||||||
} // namespace engine
|
} // namespace engine
|
||||||
|
|||||||
@ -28,6 +28,8 @@ SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
|||||||
#ifndef OSRM_ENGINE_PHANTOM_NODES_H
|
#ifndef OSRM_ENGINE_PHANTOM_NODES_H
|
||||||
#define OSRM_ENGINE_PHANTOM_NODES_H
|
#define OSRM_ENGINE_PHANTOM_NODES_H
|
||||||
|
|
||||||
|
#include <vector>
|
||||||
|
|
||||||
#include "extractor/travel_mode.hpp"
|
#include "extractor/travel_mode.hpp"
|
||||||
|
|
||||||
#include "util/bearing.hpp"
|
#include "util/bearing.hpp"
|
||||||
@ -223,7 +225,8 @@ struct PhantomNode
|
|||||||
|
|
||||||
static_assert(sizeof(PhantomNode) == 80, "PhantomNode has more padding then expected");
|
static_assert(sizeof(PhantomNode) == 80, "PhantomNode has more padding then expected");
|
||||||
|
|
||||||
using PhantomNodePair = std::pair<PhantomNode, PhantomNode>;
|
using PhantomNodeCandidates = std::vector<PhantomNode>;
|
||||||
|
using PhantomCandidateAlternatives = std::pair<PhantomNodeCandidates, PhantomNodeCandidates>;
|
||||||
|
|
||||||
struct PhantomNodeWithDistance
|
struct PhantomNodeWithDistance
|
||||||
{
|
{
|
||||||
@ -231,11 +234,44 @@ struct PhantomNodeWithDistance
|
|||||||
double distance;
|
double distance;
|
||||||
};
|
};
|
||||||
|
|
||||||
struct PhantomNodes
|
struct PhantomEndpointCandidates
|
||||||
|
{
|
||||||
|
const PhantomNodeCandidates &source_phantoms;
|
||||||
|
const PhantomNodeCandidates &target_phantoms;
|
||||||
|
};
|
||||||
|
|
||||||
|
struct PhantomCandidatesToTarget
|
||||||
|
{
|
||||||
|
const PhantomNodeCandidates &source_phantoms;
|
||||||
|
const PhantomNode &target_phantom;
|
||||||
|
};
|
||||||
|
|
||||||
|
inline util::Coordinate candidatesSnappedLocation(const PhantomNodeCandidates &candidates)
|
||||||
|
{
|
||||||
|
BOOST_ASSERT(!candidates.empty());
|
||||||
|
return candidates.front().location;
|
||||||
|
}
|
||||||
|
|
||||||
|
inline util::Coordinate candidatesInputLocation(const PhantomNodeCandidates &candidates)
|
||||||
|
{
|
||||||
|
BOOST_ASSERT(!candidates.empty());
|
||||||
|
return candidates.front().input_location;
|
||||||
|
}
|
||||||
|
|
||||||
|
inline bool candidatesHaveComponent(const PhantomNodeCandidates &candidates, uint32_t component_id)
|
||||||
|
{
|
||||||
|
return std::any_of(
|
||||||
|
candidates.begin(), candidates.end(), [component_id](const PhantomNode &node) {
|
||||||
|
return node.component.id == component_id;
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
struct PhantomEndpoints
|
||||||
{
|
{
|
||||||
PhantomNode source_phantom;
|
PhantomNode source_phantom;
|
||||||
PhantomNode target_phantom;
|
PhantomNode target_phantom;
|
||||||
};
|
};
|
||||||
|
|
||||||
} // namespace engine
|
} // namespace engine
|
||||||
} // namespace osrm
|
} // namespace osrm
|
||||||
|
|
||||||
|
|||||||
@ -99,64 +99,67 @@ class BasePlugin
|
|||||||
return Status::Error;
|
return Status::Error;
|
||||||
}
|
}
|
||||||
|
|
||||||
// Decides whether to use the phantom node from a big or small component if both are found.
|
// Decides whether to use the phantom candidates from big or small components if both are found.
|
||||||
// Returns true if all phantom nodes are in the same component after snapping.
|
std::vector<PhantomNodeCandidates>
|
||||||
std::vector<PhantomNode>
|
SnapPhantomNodes(std::vector<PhantomCandidateAlternatives> alternatives_list) const
|
||||||
SnapPhantomNodes(const std::vector<PhantomNodePair> &phantom_node_pair_list) const
|
|
||||||
{
|
{
|
||||||
const auto check_component_id_is_tiny =
|
|
||||||
[](const std::pair<PhantomNode, PhantomNode> &phantom_pair) {
|
|
||||||
return phantom_pair.first.component.is_tiny;
|
|
||||||
};
|
|
||||||
|
|
||||||
// are all phantoms from a tiny cc?
|
// are all phantoms from a tiny cc?
|
||||||
const auto check_all_in_same_component =
|
const auto all_in_same_tiny_component =
|
||||||
[](const std::vector<std::pair<PhantomNode, PhantomNode>> &nodes) {
|
[](const std::vector<PhantomCandidateAlternatives> &alts_list) {
|
||||||
const auto component_id = nodes.front().first.component.id;
|
return std::any_of(
|
||||||
|
alts_list.front().first.begin(),
|
||||||
return std::all_of(std::begin(nodes),
|
alts_list.front().first.end(),
|
||||||
std::end(nodes),
|
// For each of the first possible phantoms, check if all other
|
||||||
[component_id](const PhantomNodePair &phantom_pair) {
|
// positions in the list have a phantom from the same small component.
|
||||||
return component_id == phantom_pair.first.component.id;
|
[&](const PhantomNode &phantom) {
|
||||||
});
|
if (!phantom.component.is_tiny)
|
||||||
|
{
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
const auto component_id = phantom.component.id;
|
||||||
|
return std::all_of(
|
||||||
|
std::next(alts_list.begin()),
|
||||||
|
std::end(alts_list),
|
||||||
|
[component_id](const PhantomCandidateAlternatives &alternatives) {
|
||||||
|
return candidatesHaveComponent(alternatives.first, component_id);
|
||||||
|
});
|
||||||
|
});
|
||||||
};
|
};
|
||||||
|
|
||||||
const auto fallback_to_big_component =
|
// Move the alternative into the final list
|
||||||
[](const std::pair<PhantomNode, PhantomNode> &phantom_pair) {
|
const auto fallback_to_big_component = [](PhantomCandidateAlternatives &alternatives) {
|
||||||
if (phantom_pair.first.component.is_tiny && phantom_pair.second.IsValid() &&
|
auto no_big_alternative = alternatives.second.empty();
|
||||||
!phantom_pair.second.component.is_tiny)
|
return no_big_alternative ? std::move(alternatives.first)
|
||||||
{
|
: std::move(alternatives.second);
|
||||||
return phantom_pair.second;
|
};
|
||||||
}
|
|
||||||
return phantom_pair.first;
|
|
||||||
};
|
|
||||||
|
|
||||||
const auto use_closed_phantom =
|
// Move the alternative into the final list
|
||||||
[](const std::pair<PhantomNode, PhantomNode> &phantom_pair) {
|
const auto use_closed_phantom = [](PhantomCandidateAlternatives &alternatives) {
|
||||||
return phantom_pair.first;
|
return std::move(alternatives.first);
|
||||||
};
|
};
|
||||||
|
|
||||||
const bool every_phantom_is_in_tiny_cc = std::all_of(std::begin(phantom_node_pair_list),
|
const auto no_alternatives =
|
||||||
std::end(phantom_node_pair_list),
|
std::all_of(alternatives_list.begin(),
|
||||||
check_component_id_is_tiny);
|
alternatives_list.end(),
|
||||||
auto all_in_same_component = check_all_in_same_component(phantom_node_pair_list);
|
[](const PhantomCandidateAlternatives &alternatives) {
|
||||||
|
return alternatives.second.empty();
|
||||||
std::vector<PhantomNode> snapped_phantoms;
|
});
|
||||||
snapped_phantoms.reserve(phantom_node_pair_list.size());
|
|
||||||
|
|
||||||
|
std::vector<PhantomNodeCandidates> snapped_phantoms;
|
||||||
|
snapped_phantoms.reserve(alternatives_list.size());
|
||||||
// The only case we don't snap to the big component if all phantoms are in the same small
|
// The only case we don't snap to the big component if all phantoms are in the same small
|
||||||
// component
|
// component
|
||||||
if (every_phantom_is_in_tiny_cc && all_in_same_component)
|
if (no_alternatives || all_in_same_tiny_component(alternatives_list))
|
||||||
{
|
{
|
||||||
std::transform(phantom_node_pair_list.begin(),
|
std::transform(alternatives_list.begin(),
|
||||||
phantom_node_pair_list.end(),
|
alternatives_list.end(),
|
||||||
std::back_inserter(snapped_phantoms),
|
std::back_inserter(snapped_phantoms),
|
||||||
use_closed_phantom);
|
use_closed_phantom);
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
std::transform(phantom_node_pair_list.begin(),
|
std::transform(alternatives_list.begin(),
|
||||||
phantom_node_pair_list.end(),
|
alternatives_list.end(),
|
||||||
std::back_inserter(snapped_phantoms),
|
std::back_inserter(snapped_phantoms),
|
||||||
fallback_to_big_component);
|
fallback_to_big_component);
|
||||||
}
|
}
|
||||||
@ -181,35 +184,26 @@ class BasePlugin
|
|||||||
|
|
||||||
for (const auto i : util::irange<std::size_t>(0UL, parameters.coordinates.size()))
|
for (const auto i : util::irange<std::size_t>(0UL, parameters.coordinates.size()))
|
||||||
{
|
{
|
||||||
Approach approach = engine::Approach::UNRESTRICTED;
|
if (use_hints && parameters.hints[i] && !parameters.hints[i]->segment_hints.empty() &&
|
||||||
if (use_approaches && parameters.approaches[i])
|
|
||||||
approach = parameters.approaches[i].get();
|
|
||||||
|
|
||||||
if (use_hints && parameters.hints[i] &&
|
|
||||||
parameters.hints[i]->IsValid(parameters.coordinates[i], facade))
|
parameters.hints[i]->IsValid(parameters.coordinates[i], facade))
|
||||||
{
|
{
|
||||||
phantom_nodes[i].push_back(PhantomNodeWithDistance{
|
for (const auto &seg_hint : parameters.hints[i]->segment_hints)
|
||||||
parameters.hints[i]->phantom,
|
{
|
||||||
util::coordinate_calculation::greatCircleDistance(
|
phantom_nodes[i].push_back(PhantomNodeWithDistance{
|
||||||
parameters.coordinates[i], parameters.hints[i]->phantom.location),
|
seg_hint.phantom,
|
||||||
});
|
util::coordinate_calculation::greatCircleDistance(
|
||||||
|
parameters.coordinates[i], seg_hint.phantom.location)});
|
||||||
|
}
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
if (use_bearings && parameters.bearings[i])
|
|
||||||
{
|
phantom_nodes[i] = facade.NearestPhantomNodesInRange(
|
||||||
phantom_nodes[i] =
|
parameters.coordinates[i],
|
||||||
facade.NearestPhantomNodesInRange(parameters.coordinates[i],
|
radiuses[i],
|
||||||
radiuses[i],
|
use_bearings ? parameters.bearings[i] : boost::none,
|
||||||
parameters.bearings[i]->bearing,
|
use_approaches && parameters.approaches[i] ? parameters.approaches[i].get()
|
||||||
parameters.bearings[i]->range,
|
: engine::Approach::UNRESTRICTED,
|
||||||
approach,
|
use_all_edges);
|
||||||
use_all_edges);
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
phantom_nodes[i] = facade.NearestPhantomNodesInRange(
|
|
||||||
parameters.coordinates[i], radiuses[i], approach, use_all_edges);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
return phantom_nodes;
|
return phantom_nodes;
|
||||||
@ -218,7 +212,7 @@ class BasePlugin
|
|||||||
std::vector<std::vector<PhantomNodeWithDistance>>
|
std::vector<std::vector<PhantomNodeWithDistance>>
|
||||||
GetPhantomNodes(const datafacade::BaseDataFacade &facade,
|
GetPhantomNodes(const datafacade::BaseDataFacade &facade,
|
||||||
const api::BaseParameters ¶meters,
|
const api::BaseParameters ¶meters,
|
||||||
unsigned number_of_results) const
|
size_t number_of_results) const
|
||||||
{
|
{
|
||||||
std::vector<std::vector<PhantomNodeWithDistance>> phantom_nodes(
|
std::vector<std::vector<PhantomNodeWithDistance>> phantom_nodes(
|
||||||
parameters.coordinates.size());
|
parameters.coordinates.size());
|
||||||
@ -231,56 +225,26 @@ class BasePlugin
|
|||||||
BOOST_ASSERT(parameters.IsValid());
|
BOOST_ASSERT(parameters.IsValid());
|
||||||
for (const auto i : util::irange<std::size_t>(0UL, parameters.coordinates.size()))
|
for (const auto i : util::irange<std::size_t>(0UL, parameters.coordinates.size()))
|
||||||
{
|
{
|
||||||
Approach approach = engine::Approach::UNRESTRICTED;
|
if (use_hints && parameters.hints[i] && !parameters.hints[i]->segment_hints.empty() &&
|
||||||
if (use_approaches && parameters.approaches[i])
|
|
||||||
approach = parameters.approaches[i].get();
|
|
||||||
|
|
||||||
if (use_hints && parameters.hints[i] &&
|
|
||||||
parameters.hints[i]->IsValid(parameters.coordinates[i], facade))
|
parameters.hints[i]->IsValid(parameters.coordinates[i], facade))
|
||||||
{
|
{
|
||||||
phantom_nodes[i].push_back(PhantomNodeWithDistance{
|
for (const auto &seg_hint : parameters.hints[i]->segment_hints)
|
||||||
parameters.hints[i]->phantom,
|
{
|
||||||
util::coordinate_calculation::greatCircleDistance(
|
phantom_nodes[i].push_back(PhantomNodeWithDistance{
|
||||||
parameters.coordinates[i], parameters.hints[i]->phantom.location),
|
seg_hint.phantom,
|
||||||
});
|
util::coordinate_calculation::greatCircleDistance(
|
||||||
|
parameters.coordinates[i], seg_hint.phantom.location)});
|
||||||
|
}
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (use_bearings && parameters.bearings[i])
|
phantom_nodes[i] = facade.NearestPhantomNodes(
|
||||||
{
|
parameters.coordinates[i],
|
||||||
if (use_radiuses && parameters.radiuses[i])
|
number_of_results,
|
||||||
{
|
use_radiuses ? parameters.radiuses[i] : boost::none,
|
||||||
phantom_nodes[i] = facade.NearestPhantomNodes(parameters.coordinates[i],
|
use_bearings ? parameters.bearings[i] : boost::none,
|
||||||
number_of_results,
|
use_approaches && parameters.approaches[i] ? parameters.approaches[i].get()
|
||||||
*parameters.radiuses[i],
|
: engine::Approach::UNRESTRICTED);
|
||||||
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);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// we didn't find a fitting node, return error
|
// we didn't find a fitting node, return error
|
||||||
if (phantom_nodes[i].empty())
|
if (phantom_nodes[i].empty())
|
||||||
@ -291,10 +255,11 @@ class BasePlugin
|
|||||||
return phantom_nodes;
|
return phantom_nodes;
|
||||||
}
|
}
|
||||||
|
|
||||||
std::vector<PhantomNodePair> GetPhantomNodes(const datafacade::BaseDataFacade &facade,
|
std::vector<PhantomCandidateAlternatives>
|
||||||
const api::BaseParameters ¶meters) const
|
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_hints = !parameters.hints.empty();
|
||||||
const bool use_bearings = !parameters.bearings.empty();
|
const bool use_bearings = !parameters.bearings.empty();
|
||||||
@ -305,87 +270,57 @@ class BasePlugin
|
|||||||
BOOST_ASSERT(parameters.IsValid());
|
BOOST_ASSERT(parameters.IsValid());
|
||||||
for (const auto i : util::irange<std::size_t>(0UL, parameters.coordinates.size()))
|
for (const auto i : util::irange<std::size_t>(0UL, parameters.coordinates.size()))
|
||||||
{
|
{
|
||||||
Approach approach = engine::Approach::UNRESTRICTED;
|
if (use_hints && parameters.hints[i] && !parameters.hints[i]->segment_hints.empty() &&
|
||||||
if (use_approaches && parameters.approaches[i])
|
|
||||||
approach = parameters.approaches[i].get();
|
|
||||||
|
|
||||||
if (use_hints && parameters.hints[i] &&
|
|
||||||
parameters.hints[i]->IsValid(parameters.coordinates[i], facade))
|
parameters.hints[i]->IsValid(parameters.coordinates[i], facade))
|
||||||
{
|
{
|
||||||
phantom_node_pairs[i].first = parameters.hints[i]->phantom;
|
std::transform(parameters.hints[i]->segment_hints.begin(),
|
||||||
|
parameters.hints[i]->segment_hints.end(),
|
||||||
|
std::back_inserter(alternatives[i].first),
|
||||||
|
[](const auto &seg_hint) { return seg_hint.phantom; });
|
||||||
// we don't set the second one - it will be marked as invalid
|
// we don't set the second one - it will be marked as invalid
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (use_bearings && parameters.bearings[i])
|
alternatives[i] = facade.NearestCandidatesWithAlternativeFromBigComponent(
|
||||||
{
|
parameters.coordinates[i],
|
||||||
if (use_radiuses && parameters.radiuses[i])
|
use_radiuses ? parameters.radiuses[i] : boost::none,
|
||||||
{
|
use_bearings ? parameters.bearings[i] : boost::none,
|
||||||
phantom_node_pairs[i] =
|
use_approaches && parameters.approaches[i] ? parameters.approaches[i].get()
|
||||||
facade.NearestPhantomNodeWithAlternativeFromBigComponent(
|
: engine::Approach::UNRESTRICTED,
|
||||||
parameters.coordinates[i],
|
use_all_edges);
|
||||||
*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);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// we didn't find a fitting node, return error
|
// we didn't find a fitting node, return error
|
||||||
if (!phantom_node_pairs[i].first.IsValid())
|
if (alternatives[i].first.empty())
|
||||||
{
|
{
|
||||||
// This ensures the list of phantom nodes only consists of valid nodes.
|
// This ensures the list of phantom nodes only consists of valid nodes.
|
||||||
// We can use this on the call-site to detect an error.
|
// We can use this on the call-site to detect an error.
|
||||||
phantom_node_pairs.pop_back();
|
alternatives.pop_back();
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
BOOST_ASSERT(phantom_node_pairs[i].first.IsValid());
|
|
||||||
BOOST_ASSERT(phantom_node_pairs[i].second.IsValid());
|
BOOST_ASSERT(!alternatives[i].first.empty());
|
||||||
}
|
}
|
||||||
return phantom_node_pairs;
|
return alternatives;
|
||||||
}
|
}
|
||||||
|
|
||||||
std::string MissingPhantomErrorMessage(const std::vector<PhantomNodePair> &phantom_nodes,
|
std::string
|
||||||
const std::vector<util::Coordinate> &coordinates) const
|
MissingPhantomErrorMessage(const std::vector<PhantomCandidateAlternatives> &alternatives,
|
||||||
|
const std::vector<util::Coordinate> &coordinates) const
|
||||||
{
|
{
|
||||||
BOOST_ASSERT(phantom_nodes.size() < coordinates.size());
|
BOOST_ASSERT(alternatives.size() < coordinates.size());
|
||||||
auto mismatch = std::mismatch(phantom_nodes.begin(),
|
auto mismatch =
|
||||||
phantom_nodes.end(),
|
std::mismatch(alternatives.begin(),
|
||||||
coordinates.begin(),
|
alternatives.end(),
|
||||||
coordinates.end(),
|
coordinates.begin(),
|
||||||
[](const auto &phantom_node, const auto &coordinate) {
|
coordinates.end(),
|
||||||
return phantom_node.first.input_location == coordinate;
|
[](const auto &candidates_pair, const auto &coordinate) {
|
||||||
});
|
return std::any_of(candidates_pair.first.begin(),
|
||||||
std::size_t missing_index = std::distance(phantom_nodes.begin(), mismatch.first);
|
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 ") +
|
return std::string("Could not find a matching segment for coordinate ") +
|
||||||
std::to_string(missing_index);
|
std::to_string(missing_index);
|
||||||
}
|
}
|
||||||
|
|||||||
@ -31,7 +31,7 @@ class TripPlugin final : public BasePlugin
|
|||||||
const int max_locations_trip;
|
const int max_locations_trip;
|
||||||
|
|
||||||
InternalRouteResult ComputeRoute(const RoutingAlgorithmsInterface &algorithms,
|
InternalRouteResult ComputeRoute(const RoutingAlgorithmsInterface &algorithms,
|
||||||
const std::vector<PhantomNode> &phantom_node_list,
|
const std::vector<PhantomNodeCandidates> &candidates_list,
|
||||||
const std::vector<NodeID> &trip,
|
const std::vector<NodeID> &trip,
|
||||||
const bool roundtrip) const;
|
const bool roundtrip) const;
|
||||||
|
|
||||||
|
|||||||
@ -20,18 +20,18 @@ class RoutingAlgorithmsInterface
|
|||||||
{
|
{
|
||||||
public:
|
public:
|
||||||
virtual InternalManyRoutesResult
|
virtual InternalManyRoutesResult
|
||||||
AlternativePathSearch(const PhantomNodes &phantom_node_pair,
|
AlternativePathSearch(const PhantomEndpointCandidates &endpoint_candidates,
|
||||||
unsigned number_of_alternatives) const = 0;
|
unsigned number_of_alternatives) const = 0;
|
||||||
|
|
||||||
virtual InternalRouteResult
|
virtual InternalRouteResult
|
||||||
ShortestPathSearch(const std::vector<PhantomNodes> &phantom_node_pair,
|
ShortestPathSearch(const std::vector<PhantomNodeCandidates> &waypoint_candidates,
|
||||||
const boost::optional<bool> continue_straight_at_waypoint) const = 0;
|
const boost::optional<bool> continue_straight_at_waypoint) const = 0;
|
||||||
|
|
||||||
virtual InternalRouteResult
|
virtual InternalRouteResult
|
||||||
DirectShortestPathSearch(const PhantomNodes &phantom_node_pair) const = 0;
|
DirectShortestPathSearch(const PhantomEndpointCandidates &endpoint_candidates) const = 0;
|
||||||
|
|
||||||
virtual std::pair<std::vector<EdgeDuration>, std::vector<EdgeDistance>>
|
virtual std::pair<std::vector<EdgeDuration>, std::vector<EdgeDistance>>
|
||||||
ManyToManySearch(const std::vector<PhantomNode> &phantom_nodes,
|
ManyToManySearch(const std::vector<PhantomNodeCandidates> &candidates_list,
|
||||||
const std::vector<std::size_t> &source_indices,
|
const std::vector<std::size_t> &source_indices,
|
||||||
const std::vector<std::size_t> &target_indices,
|
const std::vector<std::size_t> &target_indices,
|
||||||
const bool calculate_distance) const = 0;
|
const bool calculate_distance) const = 0;
|
||||||
@ -73,18 +73,18 @@ template <typename Algorithm> class RoutingAlgorithms final : public RoutingAlgo
|
|||||||
virtual ~RoutingAlgorithms() = default;
|
virtual ~RoutingAlgorithms() = default;
|
||||||
|
|
||||||
InternalManyRoutesResult
|
InternalManyRoutesResult
|
||||||
AlternativePathSearch(const PhantomNodes &phantom_node_pair,
|
AlternativePathSearch(const PhantomEndpointCandidates &endpoint_candidates,
|
||||||
unsigned number_of_alternatives) const final override;
|
unsigned number_of_alternatives) const final override;
|
||||||
|
|
||||||
InternalRouteResult ShortestPathSearch(
|
InternalRouteResult ShortestPathSearch(
|
||||||
const std::vector<PhantomNodes> &phantom_node_pair,
|
const std::vector<PhantomNodeCandidates> &waypoint_candidates,
|
||||||
const boost::optional<bool> continue_straight_at_waypoint) const final override;
|
const boost::optional<bool> continue_straight_at_waypoint) const final override;
|
||||||
|
|
||||||
InternalRouteResult
|
InternalRouteResult DirectShortestPathSearch(
|
||||||
DirectShortestPathSearch(const PhantomNodes &phantom_nodes) const final override;
|
const PhantomEndpointCandidates &endpoint_candidates) const final override;
|
||||||
|
|
||||||
virtual std::pair<std::vector<EdgeDuration>, std::vector<EdgeDistance>>
|
std::pair<std::vector<EdgeDuration>, std::vector<EdgeDistance>>
|
||||||
ManyToManySearch(const std::vector<PhantomNode> &phantom_nodes,
|
ManyToManySearch(const std::vector<PhantomNodeCandidates> &candidates_list,
|
||||||
const std::vector<std::size_t> &source_indices,
|
const std::vector<std::size_t> &source_indices,
|
||||||
const std::vector<std::size_t> &target_indices,
|
const std::vector<std::size_t> &target_indices,
|
||||||
const bool calculate_distance) const final override;
|
const bool calculate_distance) const final override;
|
||||||
@ -150,28 +150,27 @@ template <typename Algorithm> class RoutingAlgorithms final : public RoutingAlgo
|
|||||||
};
|
};
|
||||||
|
|
||||||
template <typename Algorithm>
|
template <typename Algorithm>
|
||||||
InternalManyRoutesResult
|
InternalManyRoutesResult RoutingAlgorithms<Algorithm>::AlternativePathSearch(
|
||||||
RoutingAlgorithms<Algorithm>::AlternativePathSearch(const PhantomNodes &phantom_node_pair,
|
const PhantomEndpointCandidates &endpoint_candidates, unsigned number_of_alternatives) const
|
||||||
unsigned number_of_alternatives) const
|
|
||||||
{
|
{
|
||||||
return routing_algorithms::alternativePathSearch(
|
return routing_algorithms::alternativePathSearch(
|
||||||
heaps, *facade, phantom_node_pair, number_of_alternatives);
|
heaps, *facade, endpoint_candidates, number_of_alternatives);
|
||||||
}
|
}
|
||||||
|
|
||||||
template <typename Algorithm>
|
template <typename Algorithm>
|
||||||
InternalRouteResult RoutingAlgorithms<Algorithm>::ShortestPathSearch(
|
InternalRouteResult RoutingAlgorithms<Algorithm>::ShortestPathSearch(
|
||||||
const std::vector<PhantomNodes> &phantom_node_pair,
|
const std::vector<PhantomNodeCandidates> &waypoint_candidates,
|
||||||
const boost::optional<bool> continue_straight_at_waypoint) const
|
const boost::optional<bool> continue_straight_at_waypoint) const
|
||||||
{
|
{
|
||||||
return routing_algorithms::shortestPathSearch(
|
return routing_algorithms::shortestPathSearch(
|
||||||
heaps, *facade, phantom_node_pair, continue_straight_at_waypoint);
|
heaps, *facade, waypoint_candidates, continue_straight_at_waypoint);
|
||||||
}
|
}
|
||||||
|
|
||||||
template <typename Algorithm>
|
template <typename Algorithm>
|
||||||
InternalRouteResult
|
InternalRouteResult RoutingAlgorithms<Algorithm>::DirectShortestPathSearch(
|
||||||
RoutingAlgorithms<Algorithm>::DirectShortestPathSearch(const PhantomNodes &phantom_nodes) const
|
const PhantomEndpointCandidates &endpoint_candidates) const
|
||||||
{
|
{
|
||||||
return routing_algorithms::directShortestPathSearch(heaps, *facade, phantom_nodes);
|
return routing_algorithms::directShortestPathSearch(heaps, *facade, endpoint_candidates);
|
||||||
}
|
}
|
||||||
|
|
||||||
template <typename Algorithm>
|
template <typename Algorithm>
|
||||||
@ -193,30 +192,31 @@ inline routing_algorithms::SubMatchingList RoutingAlgorithms<Algorithm>::MapMatc
|
|||||||
|
|
||||||
template <typename Algorithm>
|
template <typename Algorithm>
|
||||||
std::pair<std::vector<EdgeDuration>, std::vector<EdgeDistance>>
|
std::pair<std::vector<EdgeDuration>, std::vector<EdgeDistance>>
|
||||||
RoutingAlgorithms<Algorithm>::ManyToManySearch(const std::vector<PhantomNode> &phantom_nodes,
|
RoutingAlgorithms<Algorithm>::ManyToManySearch(
|
||||||
const std::vector<std::size_t> &_source_indices,
|
const std::vector<PhantomNodeCandidates> &candidates_list,
|
||||||
const std::vector<std::size_t> &_target_indices,
|
const std::vector<std::size_t> &_source_indices,
|
||||||
const bool calculate_distance) const
|
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 source_indices = _source_indices;
|
||||||
auto target_indices = _target_indices;
|
auto target_indices = _target_indices;
|
||||||
|
|
||||||
if (source_indices.empty())
|
if (source_indices.empty())
|
||||||
{
|
{
|
||||||
source_indices.resize(phantom_nodes.size());
|
source_indices.resize(candidates_list.size());
|
||||||
std::iota(source_indices.begin(), source_indices.end(), 0);
|
std::iota(source_indices.begin(), source_indices.end(), 0);
|
||||||
}
|
}
|
||||||
if (target_indices.empty())
|
if (target_indices.empty())
|
||||||
{
|
{
|
||||||
target_indices.resize(phantom_nodes.size());
|
target_indices.resize(candidates_list.size());
|
||||||
std::iota(target_indices.begin(), target_indices.end(), 0);
|
std::iota(target_indices.begin(), target_indices.end(), 0);
|
||||||
}
|
}
|
||||||
|
|
||||||
return routing_algorithms::manyToManySearch(heaps,
|
return routing_algorithms::manyToManySearch(heaps,
|
||||||
*facade,
|
*facade,
|
||||||
phantom_nodes,
|
candidates_list,
|
||||||
std::move(source_indices),
|
std::move(source_indices),
|
||||||
std::move(target_indices),
|
std::move(target_indices),
|
||||||
calculate_distance);
|
calculate_distance);
|
||||||
|
|||||||
@ -18,12 +18,12 @@ namespace routing_algorithms
|
|||||||
|
|
||||||
InternalManyRoutesResult alternativePathSearch(SearchEngineData<ch::Algorithm> &search_engine_data,
|
InternalManyRoutesResult alternativePathSearch(SearchEngineData<ch::Algorithm> &search_engine_data,
|
||||||
const DataFacade<ch::Algorithm> &facade,
|
const DataFacade<ch::Algorithm> &facade,
|
||||||
const PhantomNodes &phantom_node_pair,
|
const PhantomEndpointCandidates &endpoint_candidates,
|
||||||
unsigned number_of_alternatives);
|
unsigned number_of_alternatives);
|
||||||
|
|
||||||
InternalManyRoutesResult alternativePathSearch(SearchEngineData<mld::Algorithm> &search_engine_data,
|
InternalManyRoutesResult alternativePathSearch(SearchEngineData<mld::Algorithm> &search_engine_data,
|
||||||
const DataFacade<mld::Algorithm> &facade,
|
const DataFacade<mld::Algorithm> &facade,
|
||||||
const PhantomNodes &phantom_node_pair,
|
const PhantomEndpointCandidates &endpoint_candidates,
|
||||||
unsigned number_of_alternatives);
|
unsigned number_of_alternatives);
|
||||||
|
|
||||||
} // namespace routing_algorithms
|
} // namespace routing_algorithms
|
||||||
|
|||||||
@ -24,7 +24,7 @@ namespace routing_algorithms
|
|||||||
template <typename Algorithm>
|
template <typename Algorithm>
|
||||||
InternalRouteResult directShortestPathSearch(SearchEngineData<Algorithm> &engine_working_data,
|
InternalRouteResult directShortestPathSearch(SearchEngineData<Algorithm> &engine_working_data,
|
||||||
const DataFacade<Algorithm> &facade,
|
const DataFacade<Algorithm> &facade,
|
||||||
const PhantomNodes &phantom_nodes);
|
const PhantomEndpointCandidates &endpoint_candidates);
|
||||||
|
|
||||||
} // namespace routing_algorithms
|
} // namespace routing_algorithms
|
||||||
} // namespace engine
|
} // namespace engine
|
||||||
|
|||||||
@ -94,7 +94,7 @@ template <typename Algorithm>
|
|||||||
std::pair<std::vector<EdgeDuration>, std::vector<EdgeDistance>>
|
std::pair<std::vector<EdgeDuration>, std::vector<EdgeDistance>>
|
||||||
manyToManySearch(SearchEngineData<Algorithm> &engine_working_data,
|
manyToManySearch(SearchEngineData<Algorithm> &engine_working_data,
|
||||||
const DataFacade<Algorithm> &facade,
|
const DataFacade<Algorithm> &facade,
|
||||||
const std::vector<PhantomNode> &phantom_nodes,
|
const std::vector<PhantomNodeCandidates> &candidates_list,
|
||||||
const std::vector<std::size_t> &source_indices,
|
const std::vector<std::size_t> &source_indices,
|
||||||
const std::vector<std::size_t> &target_indices,
|
const std::vector<std::size_t> &target_indices,
|
||||||
const bool calculate_distance);
|
const bool calculate_distance);
|
||||||
|
|||||||
@ -34,20 +34,12 @@ namespace engine
|
|||||||
|
|
||||||
namespace routing_algorithms
|
namespace routing_algorithms
|
||||||
{
|
{
|
||||||
static constexpr bool FORWARD_DIRECTION = true;
|
|
||||||
static constexpr bool REVERSE_DIRECTION = false;
|
|
||||||
static constexpr bool DO_NOT_FORCE_LOOPS = false;
|
|
||||||
|
|
||||||
bool needsLoopForward(const PhantomNode &source_phantom, const PhantomNode &target_phantom);
|
namespace details
|
||||||
bool needsLoopBackwards(const PhantomNode &source_phantom, const PhantomNode &target_phantom);
|
{
|
||||||
|
template <typename Heap>
|
||||||
bool needsLoopForward(const PhantomNodes &phantoms);
|
void insertSourceInForwardHeap(Heap &forward_heap, const PhantomNode &source)
|
||||||
bool needsLoopBackwards(const PhantomNodes &phantoms);
|
|
||||||
|
|
||||||
template <typename Heap>
|
|
||||||
void insertNodesInHeaps(Heap &forward_heap, Heap &reverse_heap, const PhantomNodes &nodes)
|
|
||||||
{
|
{
|
||||||
const auto &source = nodes.source_phantom;
|
|
||||||
if (source.IsValidForwardSource())
|
if (source.IsValidForwardSource())
|
||||||
{
|
{
|
||||||
forward_heap.Insert(source.forward_segment_id.id,
|
forward_heap.Insert(source.forward_segment_id.id,
|
||||||
@ -61,8 +53,11 @@ void insertNodesInHeaps(Heap &forward_heap, Heap &reverse_heap, const PhantomNod
|
|||||||
-source.GetReverseWeightPlusOffset(),
|
-source.GetReverseWeightPlusOffset(),
|
||||||
source.reverse_segment_id.id);
|
source.reverse_segment_id.id);
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|
||||||
const auto &target = nodes.target_phantom;
|
template <typename Heap>
|
||||||
|
void insertTargetInReverseHeap(Heap &reverse_heap, const PhantomNode &target)
|
||||||
|
{
|
||||||
if (target.IsValidForwardTarget())
|
if (target.IsValidForwardTarget())
|
||||||
{
|
{
|
||||||
reverse_heap.Insert(target.forward_segment_id.id,
|
reverse_heap.Insert(target.forward_segment_id.id,
|
||||||
@ -77,52 +72,104 @@ void insertNodesInHeaps(Heap &forward_heap, Heap &reverse_heap, const PhantomNod
|
|||||||
target.reverse_segment_id.id);
|
target.reverse_segment_id.id);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
} // namespace details
|
||||||
|
static constexpr bool FORWARD_DIRECTION = true;
|
||||||
|
static constexpr bool REVERSE_DIRECTION = false;
|
||||||
|
|
||||||
template <typename ManyToManyQueryHeap>
|
// Identify nodes in the forward(reverse) search direction that will require loop forcing
|
||||||
void insertSourceInHeap(ManyToManyQueryHeap &heap, const PhantomNode &phantom_node)
|
// 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,
|
details::insertSourceInForwardHeap(forward_heap, source);
|
||||||
-phantom_node.GetForwardWeightPlusOffset(),
|
|
||||||
{phantom_node.forward_segment_id.id,
|
|
||||||
-phantom_node.GetForwardDuration(),
|
|
||||||
-phantom_node.GetForwardDistance()});
|
|
||||||
}
|
}
|
||||||
if (phantom_node.IsValidReverseSource())
|
|
||||||
|
for (const auto &target : endpoint_candidates.target_phantoms)
|
||||||
{
|
{
|
||||||
heap.Insert(phantom_node.reverse_segment_id.id,
|
details::insertTargetInReverseHeap(reverse_heap, target);
|
||||||
-phantom_node.GetReverseWeightPlusOffset(),
|
|
||||||
{phantom_node.reverse_segment_id.id,
|
|
||||||
-phantom_node.GetReverseDuration(),
|
|
||||||
-phantom_node.GetReverseDistance()});
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
template <typename ManyToManyQueryHeap>
|
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,
|
if (phantom_node.IsValidForwardSource())
|
||||||
phantom_node.GetForwardWeightPlusOffset(),
|
{
|
||||||
{phantom_node.forward_segment_id.id,
|
heap.Insert(phantom_node.forward_segment_id.id,
|
||||||
phantom_node.GetForwardDuration(),
|
-phantom_node.GetForwardWeightPlusOffset(),
|
||||||
phantom_node.GetForwardDistance()});
|
{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,
|
if (phantom_node.IsValidForwardTarget())
|
||||||
phantom_node.GetReverseWeightPlusOffset(),
|
{
|
||||||
{phantom_node.reverse_segment_id.id,
|
heap.Insert(phantom_node.forward_segment_id.id,
|
||||||
phantom_node.GetReverseDuration(),
|
phantom_node.GetForwardWeightPlusOffset(),
|
||||||
phantom_node.GetReverseDistance()});
|
{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>
|
template <typename FacadeT>
|
||||||
void annotatePath(const FacadeT &facade,
|
void annotatePath(const FacadeT &facade,
|
||||||
const PhantomNodes &phantom_node_pair,
|
const PhantomEndpoints &endpoints,
|
||||||
const std::vector<NodeID> &unpacked_nodes,
|
const std::vector<NodeID> &unpacked_nodes,
|
||||||
const std::vector<EdgeID> &unpacked_edges,
|
const std::vector<EdgeID> &unpacked_edges,
|
||||||
std::vector<PathData> &unpacked_path)
|
std::vector<PathData> &unpacked_path)
|
||||||
@ -133,14 +180,14 @@ void annotatePath(const FacadeT &facade,
|
|||||||
const auto source_node_id = unpacked_nodes.front();
|
const auto source_node_id = unpacked_nodes.front();
|
||||||
const auto target_node_id = unpacked_nodes.back();
|
const auto target_node_id = unpacked_nodes.back();
|
||||||
const bool start_traversed_in_reverse =
|
const bool start_traversed_in_reverse =
|
||||||
phantom_node_pair.source_phantom.forward_segment_id.id != source_node_id;
|
endpoints.source_phantom.forward_segment_id.id != source_node_id;
|
||||||
const bool target_traversed_in_reverse =
|
const bool target_traversed_in_reverse =
|
||||||
phantom_node_pair.target_phantom.forward_segment_id.id != target_node_id;
|
endpoints.target_phantom.forward_segment_id.id != target_node_id;
|
||||||
|
|
||||||
BOOST_ASSERT(phantom_node_pair.source_phantom.forward_segment_id.id == source_node_id ||
|
BOOST_ASSERT(endpoints.source_phantom.forward_segment_id.id == source_node_id ||
|
||||||
phantom_node_pair.source_phantom.reverse_segment_id.id == source_node_id);
|
endpoints.source_phantom.reverse_segment_id.id == source_node_id);
|
||||||
BOOST_ASSERT(phantom_node_pair.target_phantom.forward_segment_id.id == target_node_id ||
|
BOOST_ASSERT(endpoints.target_phantom.forward_segment_id.id == target_node_id ||
|
||||||
phantom_node_pair.target_phantom.reverse_segment_id.id == target_node_id);
|
endpoints.target_phantom.reverse_segment_id.id == target_node_id);
|
||||||
|
|
||||||
// datastructures to hold extracted data from geometry
|
// datastructures to hold extracted data from geometry
|
||||||
std::vector<NodeID> id_vector;
|
std::vector<NodeID> id_vector;
|
||||||
@ -180,8 +227,8 @@ void annotatePath(const FacadeT &facade,
|
|||||||
const auto geometry_index = facade.GetGeometryIndex(node_id);
|
const auto geometry_index = facade.GetGeometryIndex(node_id);
|
||||||
get_segment_geometry(geometry_index);
|
get_segment_geometry(geometry_index);
|
||||||
|
|
||||||
BOOST_ASSERT(id_vector.size() > 0);
|
BOOST_ASSERT(!id_vector.empty());
|
||||||
BOOST_ASSERT(datasource_vector.size() > 0);
|
BOOST_ASSERT(!datasource_vector.empty());
|
||||||
BOOST_ASSERT(weight_vector.size() + 1 == id_vector.size());
|
BOOST_ASSERT(weight_vector.size() + 1 == id_vector.size());
|
||||||
BOOST_ASSERT(duration_vector.size() + 1 == id_vector.size());
|
BOOST_ASSERT(duration_vector.size() + 1 == id_vector.size());
|
||||||
|
|
||||||
@ -190,11 +237,11 @@ void annotatePath(const FacadeT &facade,
|
|||||||
std::size_t start_index = 0;
|
std::size_t start_index = 0;
|
||||||
if (is_first_segment)
|
if (is_first_segment)
|
||||||
{
|
{
|
||||||
unsigned short segment_position = phantom_node_pair.source_phantom.fwd_segment_position;
|
unsigned short segment_position = endpoints.source_phantom.fwd_segment_position;
|
||||||
if (start_traversed_in_reverse)
|
if (start_traversed_in_reverse)
|
||||||
{
|
{
|
||||||
segment_position = weight_vector.size() -
|
segment_position =
|
||||||
phantom_node_pair.source_phantom.fwd_segment_position - 1;
|
weight_vector.size() - endpoints.source_phantom.fwd_segment_position - 1;
|
||||||
}
|
}
|
||||||
BOOST_ASSERT(segment_position >= 0);
|
BOOST_ASSERT(segment_position >= 0);
|
||||||
start_index = static_cast<std::size_t>(segment_position);
|
start_index = static_cast<std::size_t>(segment_position);
|
||||||
@ -214,7 +261,7 @@ void annotatePath(const FacadeT &facade,
|
|||||||
datasource_vector[segment_idx],
|
datasource_vector[segment_idx],
|
||||||
boost::none});
|
boost::none});
|
||||||
}
|
}
|
||||||
BOOST_ASSERT(unpacked_path.size() > 0);
|
BOOST_ASSERT(!unpacked_path.empty());
|
||||||
|
|
||||||
const auto turn_duration = facade.GetDurationPenaltyForEdgeID(turn_id);
|
const auto turn_duration = facade.GetDurationPenaltyForEdgeID(turn_id);
|
||||||
const auto turn_weight = facade.GetWeightPenaltyForEdgeID(turn_id);
|
const auto turn_weight = facade.GetWeightPenaltyForEdgeID(turn_id);
|
||||||
@ -237,19 +284,17 @@ void annotatePath(const FacadeT &facade,
|
|||||||
{
|
{
|
||||||
if (is_local_path)
|
if (is_local_path)
|
||||||
{
|
{
|
||||||
start_index =
|
start_index = weight_vector.size() - endpoints.source_phantom.fwd_segment_position - 1;
|
||||||
weight_vector.size() - phantom_node_pair.source_phantom.fwd_segment_position - 1;
|
|
||||||
}
|
}
|
||||||
end_index =
|
end_index = weight_vector.size() - endpoints.target_phantom.fwd_segment_position - 1;
|
||||||
weight_vector.size() - phantom_node_pair.target_phantom.fwd_segment_position - 1;
|
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
if (is_local_path)
|
if (is_local_path)
|
||||||
{
|
{
|
||||||
start_index = phantom_node_pair.source_phantom.fwd_segment_position;
|
start_index = endpoints.source_phantom.fwd_segment_position;
|
||||||
}
|
}
|
||||||
end_index = phantom_node_pair.target_phantom.fwd_segment_position;
|
end_index = endpoints.target_phantom.fwd_segment_position;
|
||||||
}
|
}
|
||||||
|
|
||||||
// Given the following compressed geometry:
|
// Given the following compressed geometry:
|
||||||
@ -277,11 +322,11 @@ void annotatePath(const FacadeT &facade,
|
|||||||
if (!unpacked_path.empty())
|
if (!unpacked_path.empty())
|
||||||
{
|
{
|
||||||
const auto source_weight = start_traversed_in_reverse
|
const auto source_weight = start_traversed_in_reverse
|
||||||
? phantom_node_pair.source_phantom.reverse_weight
|
? endpoints.source_phantom.reverse_weight
|
||||||
: phantom_node_pair.source_phantom.forward_weight;
|
: endpoints.source_phantom.forward_weight;
|
||||||
const auto source_duration = start_traversed_in_reverse
|
const auto source_duration = start_traversed_in_reverse
|
||||||
? phantom_node_pair.source_phantom.reverse_duration
|
? endpoints.source_phantom.reverse_duration
|
||||||
: phantom_node_pair.source_phantom.forward_duration;
|
: endpoints.source_phantom.forward_duration;
|
||||||
// The above code will create segments for (v, w), (w,x), (x, y) and (y, Z).
|
// The above code will create segments for (v, w), (w,x), (x, y) and (y, Z).
|
||||||
// However the first segment duration needs to be adjusted to the fact that the source
|
// However the first segment duration needs to be adjusted to the fact that the source
|
||||||
// phantom is in the middle of the segment. We do this by subtracting v--s from the
|
// phantom is in the middle of the segment. We do this by subtracting v--s from the
|
||||||
@ -358,12 +403,11 @@ double getPathDistance(const DataFacade<Algorithm> &facade,
|
|||||||
template <typename AlgorithmT>
|
template <typename AlgorithmT>
|
||||||
InternalRouteResult extractRoute(const DataFacade<AlgorithmT> &facade,
|
InternalRouteResult extractRoute(const DataFacade<AlgorithmT> &facade,
|
||||||
const EdgeWeight weight,
|
const EdgeWeight weight,
|
||||||
const PhantomNodes &phantom_nodes,
|
const PhantomEndpointCandidates &endpoint_candidates,
|
||||||
const std::vector<NodeID> &unpacked_nodes,
|
const std::vector<NodeID> &unpacked_nodes,
|
||||||
const std::vector<EdgeID> &unpacked_edges)
|
const std::vector<EdgeID> &unpacked_edges)
|
||||||
{
|
{
|
||||||
InternalRouteResult raw_route_data;
|
InternalRouteResult raw_route_data;
|
||||||
raw_route_data.segment_end_coordinates = {phantom_nodes};
|
|
||||||
|
|
||||||
// No path found for both target nodes?
|
// No path found for both target nodes?
|
||||||
if (INVALID_EDGE_WEIGHT == weight)
|
if (INVALID_EDGE_WEIGHT == weight)
|
||||||
@ -371,15 +415,18 @@ InternalRouteResult extractRoute(const DataFacade<AlgorithmT> &facade,
|
|||||||
return raw_route_data;
|
return raw_route_data;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
auto phantom_endpoints = endpointsFromCandidates(endpoint_candidates, unpacked_nodes);
|
||||||
|
raw_route_data.leg_endpoints = {phantom_endpoints};
|
||||||
|
|
||||||
raw_route_data.shortest_path_weight = weight;
|
raw_route_data.shortest_path_weight = weight;
|
||||||
raw_route_data.unpacked_path_segments.resize(1);
|
raw_route_data.unpacked_path_segments.resize(1);
|
||||||
raw_route_data.source_traversed_in_reverse.push_back(
|
raw_route_data.source_traversed_in_reverse.push_back(
|
||||||
(unpacked_nodes.front() != phantom_nodes.source_phantom.forward_segment_id.id));
|
(unpacked_nodes.front() != phantom_endpoints.source_phantom.forward_segment_id.id));
|
||||||
raw_route_data.target_traversed_in_reverse.push_back(
|
raw_route_data.target_traversed_in_reverse.push_back(
|
||||||
(unpacked_nodes.back() != phantom_nodes.target_phantom.forward_segment_id.id));
|
(unpacked_nodes.back() != phantom_endpoints.target_phantom.forward_segment_id.id));
|
||||||
|
|
||||||
annotatePath(facade,
|
annotatePath(facade,
|
||||||
phantom_nodes,
|
phantom_endpoints,
|
||||||
unpacked_nodes,
|
unpacked_nodes,
|
||||||
unpacked_edges,
|
unpacked_edges,
|
||||||
raw_route_data.unpacked_path_segments.front());
|
raw_route_data.unpacked_path_segments.front());
|
||||||
|
|||||||
@ -120,8 +120,8 @@ void routingStep(const DataFacade<Algorithm> &facade,
|
|||||||
NodeID &middle_node_id,
|
NodeID &middle_node_id,
|
||||||
EdgeWeight &upper_bound,
|
EdgeWeight &upper_bound,
|
||||||
EdgeWeight min_edge_offset,
|
EdgeWeight min_edge_offset,
|
||||||
const bool force_loop_forward,
|
const std::vector<NodeID> &force_loop_forward_nodes,
|
||||||
const bool force_loop_reverse)
|
const std::vector<NodeID> &force_loop_reverse_nodes)
|
||||||
{
|
{
|
||||||
auto heapNode = forward_heap.DeleteMinGetHeapNode();
|
auto heapNode = forward_heap.DeleteMinGetHeapNode();
|
||||||
const auto reverseHeapNode = reverse_heap.GetHeapNodeIfWasInserted(heapNode.node);
|
const auto reverseHeapNode = reverse_heap.GetHeapNodeIfWasInserted(heapNode.node);
|
||||||
@ -131,9 +131,8 @@ void routingStep(const DataFacade<Algorithm> &facade,
|
|||||||
const EdgeWeight new_weight = reverseHeapNode->weight + heapNode.weight;
|
const EdgeWeight new_weight = reverseHeapNode->weight + heapNode.weight;
|
||||||
if (new_weight < upper_bound)
|
if (new_weight < upper_bound)
|
||||||
{
|
{
|
||||||
// if loops are forced, they are so at the source
|
if (force_loop(force_loop_forward_nodes, heapNode) ||
|
||||||
if ((force_loop_forward && heapNode.data.parent == heapNode.node) ||
|
force_loop(force_loop_reverse_nodes, heapNode) ||
|
||||||
(force_loop_reverse && reverseHeapNode->data.parent == heapNode.node) ||
|
|
||||||
// in this case we are looking at a bi-directional way where the source
|
// in this case we are looking at a bi-directional way where the source
|
||||||
// and target phantom are on the same edge based node
|
// and target phantom are on the same edge based node
|
||||||
new_weight < 0)
|
new_weight < 0)
|
||||||
@ -398,7 +397,7 @@ template <typename RandomIter, typename FacadeT>
|
|||||||
void unpackPath(const FacadeT &facade,
|
void unpackPath(const FacadeT &facade,
|
||||||
RandomIter packed_path_begin,
|
RandomIter packed_path_begin,
|
||||||
RandomIter packed_path_end,
|
RandomIter packed_path_end,
|
||||||
const PhantomNodes &phantom_nodes,
|
const PhantomEndpoints &route_endpoints,
|
||||||
std::vector<PathData> &unpacked_path)
|
std::vector<PathData> &unpacked_path)
|
||||||
{
|
{
|
||||||
const auto nodes_number = std::distance(packed_path_begin, packed_path_end);
|
const auto nodes_number = std::distance(packed_path_begin, packed_path_end);
|
||||||
@ -422,7 +421,7 @@ void unpackPath(const FacadeT &facade,
|
|||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
annotatePath(facade, phantom_nodes, unpacked_nodes, unpacked_edges, unpacked_path);
|
annotatePath(facade, route_endpoints, unpacked_nodes, unpacked_edges, unpacked_path);
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@ -467,12 +466,35 @@ void search(SearchEngineData<Algorithm> &engine_working_data,
|
|||||||
const DataFacade<Algorithm> &facade,
|
const DataFacade<Algorithm> &facade,
|
||||||
SearchEngineData<Algorithm>::QueryHeap &forward_heap,
|
SearchEngineData<Algorithm>::QueryHeap &forward_heap,
|
||||||
SearchEngineData<Algorithm>::QueryHeap &reverse_heap,
|
SearchEngineData<Algorithm>::QueryHeap &reverse_heap,
|
||||||
std::int32_t &weight,
|
EdgeWeight &weight,
|
||||||
std::vector<NodeID> &packed_leg,
|
std::vector<NodeID> &packed_leg,
|
||||||
const bool force_loop_forward,
|
const std::vector<NodeID> &force_loop_forward_node,
|
||||||
const bool force_loop_reverse,
|
const std::vector<NodeID> &force_loop_reverse_node,
|
||||||
const PhantomNodes &phantom_nodes,
|
const EdgeWeight duration_upper_bound = INVALID_EDGE_WEIGHT);
|
||||||
const int duration_upper_bound = INVALID_EDGE_WEIGHT);
|
|
||||||
|
template <typename PhantomEndpointT>
|
||||||
|
void search(SearchEngineData<Algorithm> &engine_working_data,
|
||||||
|
const DataFacade<Algorithm> &facade,
|
||||||
|
SearchEngineData<Algorithm>::QueryHeap &forward_heap,
|
||||||
|
SearchEngineData<Algorithm>::QueryHeap &reverse_heap,
|
||||||
|
EdgeWeight &weight,
|
||||||
|
std::vector<NodeID> &packed_leg,
|
||||||
|
const std::vector<NodeID> &force_loop_forward_node,
|
||||||
|
const std::vector<NodeID> &force_loop_reverse_node,
|
||||||
|
const PhantomEndpointT & /*endpoints*/,
|
||||||
|
const EdgeWeight duration_upper_bound = INVALID_EDGE_WEIGHT)
|
||||||
|
{
|
||||||
|
// Avoid templating the CH search implementations.
|
||||||
|
return search(engine_working_data,
|
||||||
|
facade,
|
||||||
|
forward_heap,
|
||||||
|
reverse_heap,
|
||||||
|
weight,
|
||||||
|
packed_leg,
|
||||||
|
force_loop_forward_node,
|
||||||
|
force_loop_reverse_node,
|
||||||
|
duration_upper_bound);
|
||||||
|
}
|
||||||
|
|
||||||
// Requires the heaps for be empty
|
// Requires the heaps for be empty
|
||||||
// If heaps should be adjusted to be initialized outside of this function,
|
// If heaps should be adjusted to be initialized outside of this function,
|
||||||
|
|||||||
@ -33,24 +33,75 @@ namespace
|
|||||||
template <typename MultiLevelPartition>
|
template <typename MultiLevelPartition>
|
||||||
inline LevelID getNodeQueryLevel(const MultiLevelPartition &partition,
|
inline LevelID getNodeQueryLevel(const MultiLevelPartition &partition,
|
||||||
NodeID node,
|
NodeID node,
|
||||||
const PhantomNodes &phantom_nodes)
|
const PhantomNode &source,
|
||||||
|
const PhantomNode &target)
|
||||||
{
|
{
|
||||||
auto level = [&partition, node](const SegmentID &source, const SegmentID &target) {
|
auto level = [&partition, node](const SegmentID &source, const SegmentID &target) {
|
||||||
if (source.enabled && target.enabled)
|
if (source.enabled && target.enabled)
|
||||||
return partition.GetQueryLevel(source.id, target.id, node);
|
return partition.GetQueryLevel(source.id, target.id, node);
|
||||||
return INVALID_LEVEL_ID;
|
return INVALID_LEVEL_ID;
|
||||||
};
|
};
|
||||||
return std::min(std::min(level(phantom_nodes.source_phantom.forward_segment_id,
|
|
||||||
phantom_nodes.target_phantom.forward_segment_id),
|
return std::min(std::min(level(source.forward_segment_id, target.forward_segment_id),
|
||||||
level(phantom_nodes.source_phantom.forward_segment_id,
|
level(source.forward_segment_id, target.reverse_segment_id)),
|
||||||
phantom_nodes.target_phantom.reverse_segment_id)),
|
std::min(level(source.reverse_segment_id, target.forward_segment_id),
|
||||||
std::min(level(phantom_nodes.source_phantom.reverse_segment_id,
|
level(source.reverse_segment_id, target.reverse_segment_id)));
|
||||||
phantom_nodes.target_phantom.forward_segment_id),
|
|
||||||
level(phantom_nodes.source_phantom.reverse_segment_id,
|
|
||||||
phantom_nodes.target_phantom.reverse_segment_id)));
|
|
||||||
}
|
}
|
||||||
|
|
||||||
inline bool checkParentCellRestriction(CellID, const PhantomNodes &) { return true; }
|
template <typename MultiLevelPartition>
|
||||||
|
inline LevelID getNodeQueryLevel(const MultiLevelPartition &partition,
|
||||||
|
NodeID node,
|
||||||
|
const PhantomEndpoints &endpoints)
|
||||||
|
{
|
||||||
|
return getNodeQueryLevel(partition, node, endpoints.source_phantom, endpoints.target_phantom);
|
||||||
|
}
|
||||||
|
|
||||||
|
template <typename MultiLevelPartition>
|
||||||
|
inline LevelID getNodeQueryLevel(const MultiLevelPartition &partition,
|
||||||
|
NodeID node,
|
||||||
|
const PhantomCandidatesToTarget &endpoint_candidates)
|
||||||
|
{
|
||||||
|
auto min_level = std::accumulate(
|
||||||
|
endpoint_candidates.source_phantoms.begin(),
|
||||||
|
endpoint_candidates.source_phantoms.end(),
|
||||||
|
INVALID_LEVEL_ID,
|
||||||
|
[&](LevelID current_level, const PhantomNode &source) {
|
||||||
|
return std::min(
|
||||||
|
current_level,
|
||||||
|
getNodeQueryLevel(partition, node, source, endpoint_candidates.target_phantom));
|
||||||
|
});
|
||||||
|
return min_level;
|
||||||
|
}
|
||||||
|
|
||||||
|
template <typename MultiLevelPartition>
|
||||||
|
inline LevelID getNodeQueryLevel(const MultiLevelPartition &partition,
|
||||||
|
NodeID node,
|
||||||
|
const PhantomEndpointCandidates &endpoint_candidates)
|
||||||
|
{
|
||||||
|
auto min_level = std::accumulate(
|
||||||
|
endpoint_candidates.source_phantoms.begin(),
|
||||||
|
endpoint_candidates.source_phantoms.end(),
|
||||||
|
INVALID_LEVEL_ID,
|
||||||
|
[&](LevelID level_1, const PhantomNode &source) {
|
||||||
|
return std::min(
|
||||||
|
level_1,
|
||||||
|
std::accumulate(endpoint_candidates.target_phantoms.begin(),
|
||||||
|
endpoint_candidates.target_phantoms.end(),
|
||||||
|
level_1,
|
||||||
|
[&](LevelID level_2, const PhantomNode &target) {
|
||||||
|
return std::min(
|
||||||
|
level_2,
|
||||||
|
getNodeQueryLevel(partition, node, source, target));
|
||||||
|
}));
|
||||||
|
});
|
||||||
|
return min_level;
|
||||||
|
}
|
||||||
|
|
||||||
|
template <typename PhantomCandidateT>
|
||||||
|
inline bool checkParentCellRestriction(CellID, const PhantomCandidateT &)
|
||||||
|
{
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
// Restricted search (Args is LevelID, CellID):
|
// Restricted search (Args is LevelID, CellID):
|
||||||
// * use the fixed level for queries
|
// * use the fixed level for queries
|
||||||
@ -72,17 +123,23 @@ inline bool checkParentCellRestriction(CellID cell, LevelID, CellID parent)
|
|||||||
template <typename MultiLevelPartition>
|
template <typename MultiLevelPartition>
|
||||||
inline LevelID getNodeQueryLevel(const MultiLevelPartition &partition,
|
inline LevelID getNodeQueryLevel(const MultiLevelPartition &partition,
|
||||||
const NodeID node,
|
const NodeID node,
|
||||||
const PhantomNode &phantom_node)
|
const PhantomNodeCandidates &candidates)
|
||||||
{
|
{
|
||||||
auto highest_diffrent_level = [&partition, node](const SegmentID &phantom_node) {
|
auto highest_different_level = [&partition, node](const SegmentID &segment) {
|
||||||
if (phantom_node.enabled)
|
return segment.enabled ? partition.GetHighestDifferentLevel(segment.id, node)
|
||||||
return partition.GetHighestDifferentLevel(phantom_node.id, node);
|
: INVALID_LEVEL_ID;
|
||||||
return INVALID_LEVEL_ID;
|
|
||||||
};
|
};
|
||||||
|
|
||||||
const auto node_level = std::min(highest_diffrent_level(phantom_node.forward_segment_id),
|
auto node_level =
|
||||||
highest_diffrent_level(phantom_node.reverse_segment_id));
|
std::accumulate(candidates.begin(),
|
||||||
|
candidates.end(),
|
||||||
|
INVALID_LEVEL_ID,
|
||||||
|
[&](LevelID current_level, const PhantomNode &phantom_node) {
|
||||||
|
auto highest_level =
|
||||||
|
std::min(highest_different_level(phantom_node.forward_segment_id),
|
||||||
|
highest_different_level(phantom_node.reverse_segment_id));
|
||||||
|
return std::min(current_level, highest_level);
|
||||||
|
});
|
||||||
return node_level;
|
return node_level;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -92,31 +149,17 @@ inline LevelID getNodeQueryLevel(const MultiLevelPartition &partition,
|
|||||||
template <typename MultiLevelPartition>
|
template <typename MultiLevelPartition>
|
||||||
inline LevelID getNodeQueryLevel(const MultiLevelPartition &partition,
|
inline LevelID getNodeQueryLevel(const MultiLevelPartition &partition,
|
||||||
NodeID node,
|
NodeID node,
|
||||||
const std::vector<PhantomNode> &phantom_nodes,
|
const std::vector<PhantomNodeCandidates> &candidates_list,
|
||||||
const std::size_t phantom_index,
|
const std::size_t phantom_index,
|
||||||
const std::vector<std::size_t> &phantom_indices)
|
const std::vector<std::size_t> &phantom_indices)
|
||||||
{
|
{
|
||||||
auto min_level = [&partition, node](const PhantomNode &phantom_node) {
|
|
||||||
const auto &forward_segment = phantom_node.forward_segment_id;
|
|
||||||
const auto forward_level =
|
|
||||||
forward_segment.enabled ? partition.GetHighestDifferentLevel(node, forward_segment.id)
|
|
||||||
: INVALID_LEVEL_ID;
|
|
||||||
|
|
||||||
const auto &reverse_segment = phantom_node.reverse_segment_id;
|
|
||||||
const auto reverse_level =
|
|
||||||
reverse_segment.enabled ? partition.GetHighestDifferentLevel(node, reverse_segment.id)
|
|
||||||
: INVALID_LEVEL_ID;
|
|
||||||
|
|
||||||
return std::min(forward_level, reverse_level);
|
|
||||||
};
|
|
||||||
|
|
||||||
// Get minimum level over all phantoms of the highest different level with respect to node
|
// Get minimum level over all phantoms of the highest different level with respect to node
|
||||||
// This is equivalent to min_{∀ source, target} partition.GetQueryLevel(source, node, target)
|
// This is equivalent to min_{∀ source, target} partition.GetQueryLevel(source, node, target)
|
||||||
auto result = min_level(phantom_nodes[phantom_index]);
|
auto init = getNodeQueryLevel(partition, node, candidates_list[phantom_index]);
|
||||||
for (const auto &index : phantom_indices)
|
auto result = std::accumulate(
|
||||||
{
|
phantom_indices.begin(), phantom_indices.end(), init, [&](LevelID level, size_t index) {
|
||||||
result = std::min(result, min_level(phantom_nodes[index]));
|
return std::min(level, getNodeQueryLevel(partition, node, candidates_list[index]));
|
||||||
}
|
});
|
||||||
return result;
|
return result;
|
||||||
}
|
}
|
||||||
} // namespace
|
} // namespace
|
||||||
@ -229,7 +272,7 @@ template <bool DIRECTION, typename Algorithm, typename... Args>
|
|||||||
void relaxOutgoingEdges(const DataFacade<Algorithm> &facade,
|
void relaxOutgoingEdges(const DataFacade<Algorithm> &facade,
|
||||||
typename SearchEngineData<Algorithm>::QueryHeap &forward_heap,
|
typename SearchEngineData<Algorithm>::QueryHeap &forward_heap,
|
||||||
const typename SearchEngineData<Algorithm>::QueryHeap::HeapNode &heapNode,
|
const typename SearchEngineData<Algorithm>::QueryHeap::HeapNode &heapNode,
|
||||||
Args... args)
|
const Args &... args)
|
||||||
{
|
{
|
||||||
const auto &partition = facade.GetMultiLevelPartition();
|
const auto &partition = facade.GetMultiLevelPartition();
|
||||||
const auto &cells = facade.GetCellStorage();
|
const auto &cells = facade.GetCellStorage();
|
||||||
@ -344,9 +387,9 @@ void routingStep(const DataFacade<Algorithm> &facade,
|
|||||||
typename SearchEngineData<Algorithm>::QueryHeap &reverse_heap,
|
typename SearchEngineData<Algorithm>::QueryHeap &reverse_heap,
|
||||||
NodeID &middle_node,
|
NodeID &middle_node,
|
||||||
EdgeWeight &path_upper_bound,
|
EdgeWeight &path_upper_bound,
|
||||||
const bool force_loop_forward,
|
const std::vector<NodeID> &force_loop_forward_nodes,
|
||||||
const bool force_loop_reverse,
|
const std::vector<NodeID> &force_loop_reverse_nodes,
|
||||||
Args... args)
|
const Args &... args)
|
||||||
{
|
{
|
||||||
const auto heapNode = forward_heap.DeleteMinGetHeapNode();
|
const auto heapNode = forward_heap.DeleteMinGetHeapNode();
|
||||||
const auto weight = heapNode.weight;
|
const auto weight = heapNode.weight;
|
||||||
@ -366,9 +409,9 @@ void routingStep(const DataFacade<Algorithm> &facade,
|
|||||||
|
|
||||||
// MLD uses loops forcing only to prune single node paths in forward and/or
|
// MLD uses loops forcing only to prune single node paths in forward and/or
|
||||||
// backward direction (there is no need to force loops in MLD but in CH)
|
// backward direction (there is no need to force loops in MLD but in CH)
|
||||||
if (!(force_loop_forward && heapNode.data.parent == heapNode.node) &&
|
if (!force_loop(force_loop_forward_nodes, heapNode) &&
|
||||||
!(force_loop_reverse && reverseHeapNode->data.parent == heapNode.node) &&
|
!force_loop(force_loop_reverse_nodes, heapNode) && (path_weight >= 0) &&
|
||||||
(path_weight >= 0) && (path_weight < path_upper_bound))
|
(path_weight < path_upper_bound))
|
||||||
{
|
{
|
||||||
middle_node = heapNode.node;
|
middle_node = heapNode.node;
|
||||||
path_upper_bound = path_weight;
|
path_upper_bound = path_weight;
|
||||||
@ -393,10 +436,10 @@ UnpackedPath search(SearchEngineData<Algorithm> &engine_working_data,
|
|||||||
const DataFacade<Algorithm> &facade,
|
const DataFacade<Algorithm> &facade,
|
||||||
typename SearchEngineData<Algorithm>::QueryHeap &forward_heap,
|
typename SearchEngineData<Algorithm>::QueryHeap &forward_heap,
|
||||||
typename SearchEngineData<Algorithm>::QueryHeap &reverse_heap,
|
typename SearchEngineData<Algorithm>::QueryHeap &reverse_heap,
|
||||||
const bool force_loop_forward,
|
const std::vector<NodeID> &force_loop_forward_nodes,
|
||||||
const bool force_loop_reverse,
|
const std::vector<NodeID> &force_loop_reverse_nodes,
|
||||||
EdgeWeight weight_upper_bound,
|
EdgeWeight weight_upper_bound,
|
||||||
Args... args)
|
const Args &... args)
|
||||||
{
|
{
|
||||||
if (forward_heap.Empty() || reverse_heap.Empty())
|
if (forward_heap.Empty() || reverse_heap.Empty())
|
||||||
{
|
{
|
||||||
@ -423,8 +466,8 @@ UnpackedPath search(SearchEngineData<Algorithm> &engine_working_data,
|
|||||||
reverse_heap,
|
reverse_heap,
|
||||||
middle,
|
middle,
|
||||||
weight,
|
weight,
|
||||||
force_loop_forward,
|
force_loop_forward_nodes,
|
||||||
force_loop_reverse,
|
force_loop_reverse_nodes,
|
||||||
args...);
|
args...);
|
||||||
if (!forward_heap.Empty())
|
if (!forward_heap.Empty())
|
||||||
forward_heap_min = forward_heap.MinKey();
|
forward_heap_min = forward_heap.MinKey();
|
||||||
@ -436,8 +479,8 @@ UnpackedPath search(SearchEngineData<Algorithm> &engine_working_data,
|
|||||||
forward_heap,
|
forward_heap,
|
||||||
middle,
|
middle,
|
||||||
weight,
|
weight,
|
||||||
force_loop_reverse,
|
force_loop_reverse_nodes,
|
||||||
force_loop_forward,
|
force_loop_forward_nodes,
|
||||||
args...);
|
args...);
|
||||||
if (!reverse_heap.Empty())
|
if (!reverse_heap.Empty())
|
||||||
reverse_heap_min = reverse_heap.MinKey();
|
reverse_heap_min = reverse_heap.MinKey();
|
||||||
@ -494,15 +537,16 @@ UnpackedPath search(SearchEngineData<Algorithm> &engine_working_data,
|
|||||||
EdgeWeight subpath_weight;
|
EdgeWeight subpath_weight;
|
||||||
std::vector<NodeID> subpath_nodes;
|
std::vector<NodeID> subpath_nodes;
|
||||||
std::vector<EdgeID> subpath_edges;
|
std::vector<EdgeID> subpath_edges;
|
||||||
std::tie(subpath_weight, subpath_nodes, subpath_edges) = search(engine_working_data,
|
std::tie(subpath_weight, subpath_nodes, subpath_edges) =
|
||||||
facade,
|
search(engine_working_data,
|
||||||
forward_heap,
|
facade,
|
||||||
reverse_heap,
|
forward_heap,
|
||||||
force_loop_forward,
|
reverse_heap,
|
||||||
force_loop_reverse,
|
force_loop_forward_nodes,
|
||||||
INVALID_EDGE_WEIGHT,
|
force_loop_reverse_nodes,
|
||||||
sublevel,
|
INVALID_EDGE_WEIGHT,
|
||||||
parent_cell_id);
|
sublevel,
|
||||||
|
parent_cell_id);
|
||||||
BOOST_ASSERT(!subpath_edges.empty());
|
BOOST_ASSERT(!subpath_edges.empty());
|
||||||
BOOST_ASSERT(subpath_nodes.size() > 1);
|
BOOST_ASSERT(subpath_nodes.size() > 1);
|
||||||
BOOST_ASSERT(subpath_nodes.front() == source);
|
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
|
// Alias to be compatible with the CH-based search
|
||||||
template <typename Algorithm>
|
template <typename Algorithm, typename PhantomEndpointT>
|
||||||
inline void search(SearchEngineData<Algorithm> &engine_working_data,
|
inline void search(SearchEngineData<Algorithm> &engine_working_data,
|
||||||
const DataFacade<Algorithm> &facade,
|
const DataFacade<Algorithm> &facade,
|
||||||
typename SearchEngineData<Algorithm>::QueryHeap &forward_heap,
|
typename SearchEngineData<Algorithm>::QueryHeap &forward_heap,
|
||||||
typename SearchEngineData<Algorithm>::QueryHeap &reverse_heap,
|
typename SearchEngineData<Algorithm>::QueryHeap &reverse_heap,
|
||||||
EdgeWeight &weight,
|
EdgeWeight &weight,
|
||||||
std::vector<NodeID> &unpacked_nodes,
|
std::vector<NodeID> &unpacked_nodes,
|
||||||
const bool force_loop_forward,
|
const std::vector<NodeID> &force_loop_forward_node,
|
||||||
const bool force_loop_reverse,
|
const std::vector<NodeID> &force_loop_reverse_node,
|
||||||
const PhantomNodes &phantom_nodes,
|
const PhantomEndpointT &endpoints,
|
||||||
const EdgeWeight weight_upper_bound = INVALID_EDGE_WEIGHT)
|
const EdgeWeight weight_upper_bound = INVALID_EDGE_WEIGHT)
|
||||||
{
|
{
|
||||||
// TODO: change search calling interface to use unpacked_edges result
|
// TODO: change search calling interface to use unpacked_edges result
|
||||||
@ -534,10 +578,10 @@ inline void search(SearchEngineData<Algorithm> &engine_working_data,
|
|||||||
facade,
|
facade,
|
||||||
forward_heap,
|
forward_heap,
|
||||||
reverse_heap,
|
reverse_heap,
|
||||||
force_loop_forward,
|
force_loop_forward_node,
|
||||||
force_loop_reverse,
|
force_loop_reverse_node,
|
||||||
weight_upper_bound,
|
weight_upper_bound,
|
||||||
phantom_nodes);
|
endpoints);
|
||||||
}
|
}
|
||||||
|
|
||||||
// TODO: refactor CH-related stub to use unpacked_edges
|
// TODO: refactor CH-related stub to use unpacked_edges
|
||||||
@ -545,7 +589,7 @@ template <typename RandomIter, typename FacadeT>
|
|||||||
void unpackPath(const FacadeT &facade,
|
void unpackPath(const FacadeT &facade,
|
||||||
RandomIter packed_path_begin,
|
RandomIter packed_path_begin,
|
||||||
RandomIter packed_path_end,
|
RandomIter packed_path_end,
|
||||||
const PhantomNodes &phantom_nodes,
|
const PhantomEndpoints &route_endpoints,
|
||||||
std::vector<PathData> &unpacked_path)
|
std::vector<PathData> &unpacked_path)
|
||||||
{
|
{
|
||||||
const auto nodes_number = std::distance(packed_path_begin, packed_path_end);
|
const auto nodes_number = std::distance(packed_path_begin, packed_path_end);
|
||||||
@ -568,7 +612,7 @@ void unpackPath(const FacadeT &facade,
|
|||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
annotatePath(facade, phantom_nodes, unpacked_nodes, unpacked_edges, unpacked_path);
|
annotatePath(facade, route_endpoints, unpacked_nodes, unpacked_edges, unpacked_path);
|
||||||
}
|
}
|
||||||
|
|
||||||
template <typename Algorithm>
|
template <typename Algorithm>
|
||||||
@ -583,8 +627,8 @@ double getNetworkDistance(SearchEngineData<Algorithm> &engine_working_data,
|
|||||||
forward_heap.Clear();
|
forward_heap.Clear();
|
||||||
reverse_heap.Clear();
|
reverse_heap.Clear();
|
||||||
|
|
||||||
const PhantomNodes phantom_nodes{source_phantom, target_phantom};
|
const PhantomEndpoints endpoints{source_phantom, target_phantom};
|
||||||
insertNodesInHeaps(forward_heap, reverse_heap, phantom_nodes);
|
insertNodesInHeaps(forward_heap, reverse_heap, endpoints);
|
||||||
|
|
||||||
EdgeWeight weight = INVALID_EDGE_WEIGHT;
|
EdgeWeight weight = INVALID_EDGE_WEIGHT;
|
||||||
std::vector<NodeID> unpacked_nodes;
|
std::vector<NodeID> unpacked_nodes;
|
||||||
@ -593,10 +637,10 @@ double getNetworkDistance(SearchEngineData<Algorithm> &engine_working_data,
|
|||||||
facade,
|
facade,
|
||||||
forward_heap,
|
forward_heap,
|
||||||
reverse_heap,
|
reverse_heap,
|
||||||
DO_NOT_FORCE_LOOPS,
|
{},
|
||||||
DO_NOT_FORCE_LOOPS,
|
{},
|
||||||
weight_upper_bound,
|
weight_upper_bound,
|
||||||
phantom_nodes);
|
endpoints);
|
||||||
|
|
||||||
if (weight == INVALID_EDGE_WEIGHT)
|
if (weight == INVALID_EDGE_WEIGHT)
|
||||||
{
|
{
|
||||||
@ -605,7 +649,7 @@ double getNetworkDistance(SearchEngineData<Algorithm> &engine_working_data,
|
|||||||
|
|
||||||
std::vector<PathData> unpacked_path;
|
std::vector<PathData> unpacked_path;
|
||||||
|
|
||||||
annotatePath(facade, phantom_nodes, unpacked_nodes, unpacked_edges, unpacked_path);
|
annotatePath(facade, endpoints, unpacked_nodes, unpacked_edges, unpacked_path);
|
||||||
|
|
||||||
return getPathDistance(facade, unpacked_path, source_phantom, target_phantom);
|
return getPathDistance(facade, unpacked_path, source_phantom, target_phantom);
|
||||||
}
|
}
|
||||||
|
|||||||
@ -14,10 +14,11 @@ namespace routing_algorithms
|
|||||||
{
|
{
|
||||||
|
|
||||||
template <typename Algorithm>
|
template <typename Algorithm>
|
||||||
InternalRouteResult shortestPathSearch(SearchEngineData<Algorithm> &engine_working_data,
|
InternalRouteResult
|
||||||
const DataFacade<Algorithm> &facade,
|
shortestPathSearch(SearchEngineData<Algorithm> &engine_working_data,
|
||||||
const std::vector<PhantomNodes> &phantom_nodes_vector,
|
const DataFacade<Algorithm> &facade,
|
||||||
const boost::optional<bool> continue_straight_at_waypoint);
|
const std::vector<PhantomNodeCandidates> &waypoint_candidates,
|
||||||
|
const boost::optional<bool> continue_straight_at_waypoint);
|
||||||
|
|
||||||
} // namespace routing_algorithms
|
} // namespace routing_algorithms
|
||||||
} // namespace engine
|
} // 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)
|
: BaseParametersGrammar::base_type(root_rule)
|
||||||
{
|
{
|
||||||
const auto add_hint = [](engine::api::BaseParameters &base_parameters,
|
const auto add_hint = [](engine::api::BaseParameters &base_parameters,
|
||||||
const boost::optional<std::string> &hint_string) {
|
const std::vector<std::string> &hint_strings) {
|
||||||
if (hint_string)
|
if (!hint_strings.empty())
|
||||||
{
|
{
|
||||||
base_parameters.hints.emplace_back(engine::Hint::FromBase64(hint_string.get()));
|
std::vector<engine::SegmentHint> location_hints(hint_strings.size());
|
||||||
|
std::transform(hint_strings.begin(),
|
||||||
|
hint_strings.end(),
|
||||||
|
location_hints.begin(),
|
||||||
|
[](const auto &hint_string) {
|
||||||
|
return engine::SegmentHint::FromBase64(hint_string);
|
||||||
|
});
|
||||||
|
base_parameters.hints.push_back(engine::Hint{std::move(location_hints)});
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
@ -145,10 +152,11 @@ struct BaseParametersGrammar : boost::spirit::qi::grammar<Iterator, Signature>
|
|||||||
(-(qi::double_ | unlimited_rule) %
|
(-(qi::double_ | unlimited_rule) %
|
||||||
';')[ph::bind(&engine::api::BaseParameters::radiuses, qi::_r1) = qi::_1];
|
';')[ph::bind(&engine::api::BaseParameters::radiuses, qi::_r1) = qi::_1];
|
||||||
|
|
||||||
hints_rule = qi::lit("hints=") >
|
hints_rule =
|
||||||
(-qi::as_string[qi::repeat(engine::ENCODED_HINT_SIZE)[base64_char]])[ph::bind(
|
qi::lit("hints=") >
|
||||||
add_hint, qi::_r1, qi::_1)] %
|
(*qi::as_string[qi::repeat(engine::ENCODED_SEGMENT_HINT_SIZE)[base64_char]])[ph::bind(
|
||||||
';';
|
add_hint, qi::_r1, qi::_1)] %
|
||||||
|
';';
|
||||||
|
|
||||||
generate_hints_rule =
|
generate_hints_rule =
|
||||||
qi::lit("generate_hints=") >
|
qi::lit("generate_hints=") >
|
||||||
|
|||||||
@ -68,7 +68,7 @@ write(storage::tar::FileWriter &writer,
|
|||||||
|
|
||||||
/***
|
/***
|
||||||
* Static RTree for serving nearest neighbour queries
|
* Static RTree for serving nearest neighbour queries
|
||||||
* // All coordinates are pojected first to Web Mercator before the bounding boxes
|
* // All coordinates are projected first to Web Mercator before the bounding boxes
|
||||||
* // are computed, this means the internal distance metric doesn not represent meters!
|
* // are computed, this means the internal distance metric doesn not represent meters!
|
||||||
*/
|
*/
|
||||||
|
|
||||||
@ -556,8 +556,8 @@ class StaticRTree
|
|||||||
}
|
}
|
||||||
|
|
||||||
// Override filter and terminator for the desired behaviour.
|
// Override filter and terminator for the desired behaviour.
|
||||||
std::vector<EdgeDataT> Nearest(const Coordinate input_coordinate,
|
std::vector<CandidateSegment> Nearest(const Coordinate input_coordinate,
|
||||||
const std::size_t max_results) const
|
const std::size_t max_results) const
|
||||||
{
|
{
|
||||||
return Nearest(
|
return Nearest(
|
||||||
input_coordinate,
|
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>
|
template <typename FilterT, typename TerminationT>
|
||||||
std::vector<EdgeDataT> Nearest(const Coordinate input_coordinate,
|
std::vector<CandidateSegment> Nearest(const Coordinate input_coordinate,
|
||||||
const FilterT filter,
|
const FilterT filter,
|
||||||
const TerminationT terminate) const
|
const TerminationT terminate) const
|
||||||
{
|
{
|
||||||
std::vector<EdgeDataT> results;
|
std::vector<CandidateSegment> results;
|
||||||
auto projected_coordinate = web_mercator::fromWGS84(input_coordinate);
|
auto projected_coordinate = web_mercator::fromWGS84(input_coordinate);
|
||||||
Coordinate fixed_projected_coordinate{projected_coordinate};
|
Coordinate fixed_projected_coordinate{projected_coordinate};
|
||||||
// initialize queue with root element
|
// initialize queue with root element
|
||||||
@ -603,10 +603,10 @@ class StaticRTree
|
|||||||
}
|
}
|
||||||
else
|
else
|
||||||
{ // current candidate is an actual road segment
|
{ // current candidate is an actual road segment
|
||||||
// We deliberatly make a copy here, we mutate the value below
|
const auto &edge_data = m_objects[current_query_node.segment_index];
|
||||||
auto edge_data = m_objects[current_query_node.segment_index];
|
// We deliberately make an edge data copy here, we mutate the value below
|
||||||
const auto ¤t_candidate =
|
CandidateSegment current_candidate{current_query_node.fixed_projected_coordinate,
|
||||||
CandidateSegment{current_query_node.fixed_projected_coordinate, edge_data};
|
edge_data};
|
||||||
|
|
||||||
// to allow returns of no-results if too restrictive filtering, this needs to be
|
// to allow returns of no-results if too restrictive filtering, this needs to be
|
||||||
// done here even though performance would indicate that we want to stop after
|
// done here even though performance would indicate that we want to stop after
|
||||||
@ -621,11 +621,11 @@ class StaticRTree
|
|||||||
{
|
{
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
edge_data.forward_segment_id.enabled &= use_segment.first;
|
current_candidate.data.forward_segment_id.enabled &= use_segment.first;
|
||||||
edge_data.reverse_segment_id.enabled &= use_segment.second;
|
current_candidate.data.reverse_segment_id.enabled &= use_segment.second;
|
||||||
|
|
||||||
// store phantom node in result vector
|
// store phantom node in result vector
|
||||||
results.push_back(std::move(edge_data));
|
results.push_back(std::move(current_candidate));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -676,7 +676,7 @@ class StaticRTree
|
|||||||
* Iterates over all the children of a TreeNode and inserts them into the search
|
* Iterates over all the children of a TreeNode and inserts them into the search
|
||||||
* priority queue using their distance from the search coordinate as the
|
* priority queue using their distance from the search coordinate as the
|
||||||
* priority metric.
|
* priority metric.
|
||||||
* The closests distance to a box from our point is also the closest distance
|
* The closest distance to a box from our point is also the closest distance
|
||||||
* to the closest line in that box (assuming the boxes hug their contents).
|
* to the closest line in that box (assuming the boxes hug their contents).
|
||||||
*/
|
*/
|
||||||
template <class QueueT>
|
template <class QueueT>
|
||||||
|
|||||||
@ -239,10 +239,10 @@ makeWaypoint(const util::Coordinate &location, const double &distance, std::stri
|
|||||||
util::json::Object makeWaypoint(const util::Coordinate &location,
|
util::json::Object makeWaypoint(const util::Coordinate &location,
|
||||||
const double &distance,
|
const double &distance,
|
||||||
std::string name,
|
std::string name,
|
||||||
const Hint &hint)
|
const Hint &location_hints)
|
||||||
{
|
{
|
||||||
auto waypoint = makeWaypoint(location, distance, std::move(name));
|
auto waypoint = makeWaypoint(location, distance, std::move(name));
|
||||||
waypoint.values["hint"] = hint.ToBase64();
|
waypoint.values["hint"] = location_hints.ToBase64();
|
||||||
return waypoint;
|
return waypoint;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@ -3,10 +3,10 @@
|
|||||||
#include "engine/datafacade/datafacade_base.hpp"
|
#include "engine/datafacade/datafacade_base.hpp"
|
||||||
|
|
||||||
#include <boost/assert.hpp>
|
#include <boost/assert.hpp>
|
||||||
|
#include <boost/unordered_set.hpp>
|
||||||
|
|
||||||
#include <algorithm>
|
#include <algorithm>
|
||||||
#include <iterator>
|
#include <iterator>
|
||||||
#include <ostream>
|
|
||||||
#include <tuple>
|
#include <tuple>
|
||||||
|
|
||||||
namespace osrm
|
namespace osrm
|
||||||
@ -14,8 +14,8 @@ namespace osrm
|
|||||||
namespace engine
|
namespace engine
|
||||||
{
|
{
|
||||||
|
|
||||||
bool Hint::IsValid(const util::Coordinate new_input_coordinates,
|
bool SegmentHint::IsValid(const util::Coordinate new_input_coordinates,
|
||||||
const datafacade::BaseDataFacade &facade) const
|
const datafacade::BaseDataFacade &facade) const
|
||||||
{
|
{
|
||||||
auto is_same_input_coordinate = new_input_coordinates.lon == phantom.input_location.lon &&
|
auto is_same_input_coordinate = new_input_coordinates.lon == phantom.input_location.lon &&
|
||||||
new_input_coordinates.lat == phantom.input_location.lat;
|
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;
|
return is_same_input_coordinate && phantom.IsValid() && facade.GetCheckSum() == data_checksum;
|
||||||
}
|
}
|
||||||
|
|
||||||
std::string Hint::ToBase64() const
|
std::string SegmentHint::ToBase64() const
|
||||||
{
|
{
|
||||||
auto base64 = encodeBase64Bytewise(*this);
|
auto base64 = encodeBase64Bytewise(*this);
|
||||||
|
|
||||||
@ -36,9 +36,9 @@ std::string Hint::ToBase64() const
|
|||||||
return base64;
|
return base64;
|
||||||
}
|
}
|
||||||
|
|
||||||
Hint Hint::FromBase64(const std::string &base64Hint)
|
SegmentHint SegmentHint::FromBase64(const std::string &base64Hint)
|
||||||
{
|
{
|
||||||
BOOST_ASSERT_MSG(base64Hint.size() == ENCODED_HINT_SIZE, "Hint has invalid size");
|
BOOST_ASSERT_MSG(base64Hint.size() == ENCODED_SEGMENT_HINT_SIZE, "Hint has invalid size");
|
||||||
|
|
||||||
// We need mutability but don't want to change the API
|
// We need mutability but don't want to change the API
|
||||||
auto encoded = base64Hint;
|
auto encoded = base64Hint;
|
||||||
@ -47,15 +47,82 @@ Hint Hint::FromBase64(const std::string &base64Hint)
|
|||||||
std::replace(begin(encoded), end(encoded), '-', '+');
|
std::replace(begin(encoded), end(encoded), '-', '+');
|
||||||
std::replace(begin(encoded), end(encoded), '_', '/');
|
std::replace(begin(encoded), end(encoded), '_', '/');
|
||||||
|
|
||||||
return decodeBase64Bytewise<Hint>(encoded);
|
return decodeBase64Bytewise<SegmentHint>(encoded);
|
||||||
}
|
}
|
||||||
|
|
||||||
bool operator==(const Hint &lhs, const Hint &rhs)
|
bool operator==(const SegmentHint &lhs, const SegmentHint &rhs)
|
||||||
{
|
{
|
||||||
return std::tie(lhs.phantom, lhs.data_checksum) == std::tie(rhs.phantom, rhs.data_checksum);
|
return std::tie(lhs.phantom, lhs.data_checksum) == std::tie(rhs.phantom, rhs.data_checksum);
|
||||||
}
|
}
|
||||||
|
|
||||||
std::ostream &operator<<(std::ostream &out, const Hint &hint) { return out << hint.ToBase64(); }
|
bool operator!=(const SegmentHint &lhs, const SegmentHint &rhs) { return !(lhs == rhs); }
|
||||||
|
|
||||||
|
std::ostream &operator<<(std::ostream &out, const SegmentHint &hint)
|
||||||
|
{
|
||||||
|
return out << hint.ToBase64();
|
||||||
|
}
|
||||||
|
|
||||||
|
std::string Hint::ToBase64() const
|
||||||
|
{
|
||||||
|
std::string res;
|
||||||
|
for (const auto &hint : segment_hints)
|
||||||
|
{
|
||||||
|
res += hint.ToBase64();
|
||||||
|
}
|
||||||
|
return res;
|
||||||
|
}
|
||||||
|
|
||||||
|
Hint Hint::FromBase64(const std::string &base64Hint)
|
||||||
|
{
|
||||||
|
|
||||||
|
BOOST_ASSERT_MSG(base64Hint.size() % ENCODED_SEGMENT_HINT_SIZE == 0,
|
||||||
|
"SegmentHint has invalid size");
|
||||||
|
|
||||||
|
auto num_hints = base64Hint.size() / ENCODED_SEGMENT_HINT_SIZE;
|
||||||
|
std::vector<SegmentHint> res(num_hints);
|
||||||
|
|
||||||
|
for (const auto i : util::irange<std::size_t>(0UL, num_hints))
|
||||||
|
{
|
||||||
|
auto start_offset = i * ENCODED_SEGMENT_HINT_SIZE;
|
||||||
|
auto end_offset = start_offset + ENCODED_SEGMENT_HINT_SIZE;
|
||||||
|
res[i] = SegmentHint::FromBase64(
|
||||||
|
std::string(base64Hint.begin() + start_offset, base64Hint.begin() + end_offset));
|
||||||
|
}
|
||||||
|
|
||||||
|
return {std::move(res)};
|
||||||
|
}
|
||||||
|
|
||||||
|
bool Hint::IsValid(const util::Coordinate new_input_coordinates,
|
||||||
|
const datafacade::BaseDataFacade &facade) const
|
||||||
|
{
|
||||||
|
const auto all_valid =
|
||||||
|
std::all_of(segment_hints.begin(), segment_hints.end(), [&](const auto &seg_hint) {
|
||||||
|
return seg_hint.IsValid(new_input_coordinates, facade);
|
||||||
|
});
|
||||||
|
if (!all_valid)
|
||||||
|
{
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Check hints do not contain duplicate segment pairs
|
||||||
|
// We can't allow duplicates as search heaps do not support it.
|
||||||
|
boost::unordered_set<NodeID> forward_segments;
|
||||||
|
boost::unordered_set<NodeID> reverse_segments;
|
||||||
|
for (const auto &seg_hint : segment_hints)
|
||||||
|
{
|
||||||
|
const auto forward_res = forward_segments.insert(seg_hint.phantom.forward_segment_id.id);
|
||||||
|
if (!forward_res.second)
|
||||||
|
{
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
const auto backward_res = reverse_segments.insert(seg_hint.phantom.reverse_segment_id.id);
|
||||||
|
if (!backward_res.second)
|
||||||
|
{
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
} // namespace engine
|
} // namespace engine
|
||||||
} // namespace osrm
|
} // namespace osrm
|
||||||
|
|||||||
@ -4,21 +4,16 @@
|
|||||||
#include "engine/api/match_api.hpp"
|
#include "engine/api/match_api.hpp"
|
||||||
#include "engine/api/match_parameters.hpp"
|
#include "engine/api/match_parameters.hpp"
|
||||||
#include "engine/api/match_parameters_tidy.hpp"
|
#include "engine/api/match_parameters_tidy.hpp"
|
||||||
#include "engine/map_matching/bayes_classifier.hpp"
|
|
||||||
#include "engine/map_matching/sub_matching.hpp"
|
#include "engine/map_matching/sub_matching.hpp"
|
||||||
#include "util/coordinate_calculation.hpp"
|
#include "util/coordinate_calculation.hpp"
|
||||||
#include "util/integer_range.hpp"
|
#include "util/integer_range.hpp"
|
||||||
#include "util/json_util.hpp"
|
|
||||||
#include "util/string_util.hpp"
|
|
||||||
|
|
||||||
#include <cstdlib>
|
#include <cstdlib>
|
||||||
|
|
||||||
#include <algorithm>
|
#include <algorithm>
|
||||||
#include <functional>
|
#include <functional>
|
||||||
#include <iterator>
|
|
||||||
#include <memory>
|
#include <memory>
|
||||||
#include <set>
|
#include <set>
|
||||||
#include <string>
|
|
||||||
#include <vector>
|
#include <vector>
|
||||||
|
|
||||||
namespace osrm
|
namespace osrm
|
||||||
@ -28,7 +23,7 @@ namespace engine
|
|||||||
namespace plugins
|
namespace plugins
|
||||||
{
|
{
|
||||||
|
|
||||||
// Filters PhantomNodes to obtain a set of viable candiates
|
// Filters PhantomNodes to obtain a set of viable candidates
|
||||||
void filterCandidates(const std::vector<util::Coordinate> &coordinates,
|
void filterCandidates(const std::vector<util::Coordinate> &coordinates,
|
||||||
MatchPlugin::CandidateLists &candidates_lists)
|
MatchPlugin::CandidateLists &candidates_lists)
|
||||||
{
|
{
|
||||||
@ -272,20 +267,26 @@ Status MatchPlugin::HandleRequest(const RoutingAlgorithmsInterface &algorithms,
|
|||||||
|
|
||||||
// FIXME we only run this to obtain the geometry
|
// FIXME we only run this to obtain the geometry
|
||||||
// The clean way would be to get this directly from the map matching plugin
|
// The clean way would be to get this directly from the map matching plugin
|
||||||
PhantomNodes current_phantom_node_pair;
|
|
||||||
for (unsigned i = 0; i < sub_matchings[index].nodes.size() - 1; ++i)
|
for (unsigned i = 0; i < sub_matchings[index].nodes.size() - 1; ++i)
|
||||||
{
|
{
|
||||||
current_phantom_node_pair.source_phantom = sub_matchings[index].nodes[i];
|
PhantomEndpoints current_endpoints{sub_matchings[index].nodes[i],
|
||||||
current_phantom_node_pair.target_phantom = sub_matchings[index].nodes[i + 1];
|
sub_matchings[index].nodes[i + 1]};
|
||||||
BOOST_ASSERT(current_phantom_node_pair.source_phantom.IsValid());
|
BOOST_ASSERT(current_endpoints.source_phantom.IsValid());
|
||||||
BOOST_ASSERT(current_phantom_node_pair.target_phantom.IsValid());
|
BOOST_ASSERT(current_endpoints.target_phantom.IsValid());
|
||||||
sub_routes[index].segment_end_coordinates.emplace_back(current_phantom_node_pair);
|
sub_routes[index].leg_endpoints.push_back(current_endpoints);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
std::vector<PhantomNodeCandidates> waypoint_candidates;
|
||||||
|
waypoint_candidates.reserve(sub_matchings[index].nodes.size());
|
||||||
|
std::transform(sub_matchings[index].nodes.begin(),
|
||||||
|
sub_matchings[index].nodes.end(),
|
||||||
|
std::back_inserter(waypoint_candidates),
|
||||||
|
[](const auto &phantom) { return PhantomNodeCandidates{phantom}; });
|
||||||
|
|
||||||
// force uturns to be on
|
// force uturns to be on
|
||||||
// we split the phantom nodes anyway and only have bi-directional phantom nodes for
|
// we split the phantom nodes anyway and only have bi-directional phantom nodes for
|
||||||
// possible uturns
|
// possible uturns
|
||||||
sub_routes[index] =
|
sub_routes[index] = algorithms.ShortestPathSearch(waypoint_candidates, {false});
|
||||||
algorithms.ShortestPathSearch(sub_routes[index].segment_end_coordinates, {false});
|
|
||||||
BOOST_ASSERT(sub_routes[index].shortest_path_weight != INVALID_EDGE_WEIGHT);
|
BOOST_ASSERT(sub_routes[index].shortest_path_weight != INVALID_EDGE_WEIGHT);
|
||||||
if (collapse_legs)
|
if (collapse_legs)
|
||||||
{
|
{
|
||||||
|
|||||||
@ -1,10 +1,7 @@
|
|||||||
#include "engine/plugins/nearest.hpp"
|
#include "engine/plugins/nearest.hpp"
|
||||||
#include "engine/api/nearest_api.hpp"
|
#include "engine/api/nearest_api.hpp"
|
||||||
#include "engine/api/nearest_parameters.hpp"
|
#include "engine/api/nearest_parameters.hpp"
|
||||||
#include "engine/phantom_node.hpp"
|
|
||||||
#include "util/integer_range.hpp"
|
|
||||||
|
|
||||||
#include <cstddef>
|
|
||||||
#include <string>
|
#include <string>
|
||||||
|
|
||||||
#include <boost/assert.hpp>
|
#include <boost/assert.hpp>
|
||||||
|
|||||||
@ -2,17 +2,11 @@
|
|||||||
|
|
||||||
#include "engine/api/table_api.hpp"
|
#include "engine/api/table_api.hpp"
|
||||||
#include "engine/api/table_parameters.hpp"
|
#include "engine/api/table_parameters.hpp"
|
||||||
#include "engine/routing_algorithms/many_to_many.hpp"
|
|
||||||
#include "engine/search_engine_data.hpp"
|
|
||||||
#include "util/coordinate_calculation.hpp"
|
#include "util/coordinate_calculation.hpp"
|
||||||
#include "util/json_container.hpp"
|
|
||||||
#include "util/string_util.hpp"
|
#include "util/string_util.hpp"
|
||||||
|
|
||||||
#include <cstdlib>
|
#include <cstdlib>
|
||||||
|
|
||||||
#include <algorithm>
|
|
||||||
#include <memory>
|
|
||||||
#include <string>
|
|
||||||
#include <vector>
|
#include <vector>
|
||||||
|
|
||||||
#include <boost/assert.hpp>
|
#include <boost/assert.hpp>
|
||||||
@ -47,7 +41,7 @@ Status TablePlugin::HandleRequest(const RoutingAlgorithmsInterface &algorithms,
|
|||||||
return Error("InvalidOptions", "Coordinates are invalid", result);
|
return Error("InvalidOptions", "Coordinates are invalid", result);
|
||||||
}
|
}
|
||||||
|
|
||||||
if (params.bearings.size() > 0 && params.coordinates.size() != params.bearings.size())
|
if (!params.bearings.empty() && params.coordinates.size() != params.bearings.size())
|
||||||
{
|
{
|
||||||
return Error(
|
return Error(
|
||||||
"InvalidOptions", "Number of bearings does not match number of coordinates", result);
|
"InvalidOptions", "Number of bearings does not match number of coordinates", result);
|
||||||
@ -79,7 +73,7 @@ Status TablePlugin::HandleRequest(const RoutingAlgorithmsInterface &algorithms,
|
|||||||
"NoSegment", MissingPhantomErrorMessage(phantom_nodes, params.coordinates), result);
|
"NoSegment", MissingPhantomErrorMessage(phantom_nodes, params.coordinates), result);
|
||||||
}
|
}
|
||||||
|
|
||||||
auto snapped_phantoms = SnapPhantomNodes(phantom_nodes);
|
auto snapped_phantoms = SnapPhantomNodes(std::move(phantom_nodes));
|
||||||
|
|
||||||
bool request_distance = params.annotations & api::TableParameters::AnnotationsType::Distance;
|
bool request_distance = params.annotations & api::TableParameters::AnnotationsType::Distance;
|
||||||
bool request_duration = params.annotations & api::TableParameters::AnnotationsType::Duration;
|
bool request_duration = params.annotations & api::TableParameters::AnnotationsType::Duration;
|
||||||
@ -117,9 +111,11 @@ Status TablePlugin::HandleRequest(const RoutingAlgorithmsInterface &algorithms,
|
|||||||
params.fallback_coordinate_type ==
|
params.fallback_coordinate_type ==
|
||||||
api::TableParameters::FallbackCoordinateType::Input
|
api::TableParameters::FallbackCoordinateType::Input
|
||||||
? util::coordinate_calculation::greatCircleDistance(
|
? util::coordinate_calculation::greatCircleDistance(
|
||||||
source.input_location, destination.input_location)
|
candidatesInputLocation(source),
|
||||||
|
candidatesInputLocation(destination))
|
||||||
: util::coordinate_calculation::greatCircleDistance(
|
: util::coordinate_calculation::greatCircleDistance(
|
||||||
source.location, destination.location);
|
candidatesSnappedLocation(source),
|
||||||
|
candidatesSnappedLocation(destination));
|
||||||
|
|
||||||
result_tables_pair.first[table_index] =
|
result_tables_pair.first[table_index] =
|
||||||
distance_estimate / (double)params.fallback_speed;
|
distance_estimate / (double)params.fallback_speed;
|
||||||
|
|||||||
@ -20,7 +20,6 @@
|
|||||||
#include <algorithm>
|
#include <algorithm>
|
||||||
#include <numeric>
|
#include <numeric>
|
||||||
#include <string>
|
#include <string>
|
||||||
#include <unordered_map>
|
|
||||||
#include <utility>
|
#include <utility>
|
||||||
#include <vector>
|
#include <vector>
|
||||||
|
|
||||||
|
|||||||
@ -4,18 +4,12 @@
|
|||||||
#include "engine/api/trip_parameters.hpp"
|
#include "engine/api/trip_parameters.hpp"
|
||||||
#include "engine/trip/trip_brute_force.hpp"
|
#include "engine/trip/trip_brute_force.hpp"
|
||||||
#include "engine/trip/trip_farthest_insertion.hpp"
|
#include "engine/trip/trip_farthest_insertion.hpp"
|
||||||
#include "engine/trip/trip_nearest_neighbour.hpp"
|
|
||||||
#include "util/dist_table_wrapper.hpp" // to access the dist table more easily
|
#include "util/dist_table_wrapper.hpp" // to access the dist table more easily
|
||||||
#include "util/json_container.hpp"
|
|
||||||
|
|
||||||
#include <boost/assert.hpp>
|
#include <boost/assert.hpp>
|
||||||
|
|
||||||
#include <algorithm>
|
#include <algorithm>
|
||||||
#include <cstdlib>
|
|
||||||
#include <iterator>
|
|
||||||
#include <limits>
|
#include <limits>
|
||||||
#include <memory>
|
|
||||||
#include <string>
|
|
||||||
#include <utility>
|
#include <utility>
|
||||||
#include <vector>
|
#include <vector>
|
||||||
|
|
||||||
@ -41,40 +35,33 @@ bool IsSupportedParameterCombination(const bool fixed_start,
|
|||||||
|
|
||||||
// given the node order in which to visit, compute the actual route (with geometry, travel time and
|
// given the node order in which to visit, compute the actual route (with geometry, travel time and
|
||||||
// so on) and return the result
|
// so on) and return the result
|
||||||
InternalRouteResult TripPlugin::ComputeRoute(const RoutingAlgorithmsInterface &algorithms,
|
InternalRouteResult
|
||||||
const std::vector<PhantomNode> &snapped_phantoms,
|
TripPlugin::ComputeRoute(const RoutingAlgorithmsInterface &algorithms,
|
||||||
const std::vector<NodeID> &trip,
|
const std::vector<PhantomNodeCandidates> &waypoint_candidates,
|
||||||
const bool roundtrip) const
|
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
|
// return back to the first node if it is a round trip
|
||||||
if (roundtrip)
|
if (roundtrip)
|
||||||
{
|
{
|
||||||
viapoint = PhantomNodes{snapped_phantoms[trip.back()], snapped_phantoms[trip.front()]};
|
trip_candidates.push_back(waypoint_candidates[trip.front()]);
|
||||||
min_route.segment_end_coordinates.emplace_back(viapoint);
|
|
||||||
// trip comes out to be something like 0 1 4 3 2 0
|
// trip comes out to be something like 0 1 4 3 2 0
|
||||||
BOOST_ASSERT(min_route.segment_end_coordinates.size() == trip.size());
|
BOOST_ASSERT(trip_candidates.size() == trip.size() + 1);
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
// trip comes out to be something like 0 1 4 3 2, so the sizes don't match
|
// trip comes out to be something like 0 1 4 3 2
|
||||||
BOOST_ASSERT(min_route.segment_end_coordinates.size() == trip.size() - 1);
|
BOOST_ASSERT(trip_candidates.size() == trip.size());
|
||||||
}
|
}
|
||||||
|
|
||||||
min_route = algorithms.ShortestPathSearch(min_route.segment_end_coordinates, {false});
|
auto min_route = algorithms.ShortestPathSearch(trip_candidates, {false});
|
||||||
BOOST_ASSERT_MSG(min_route.shortest_path_weight < INVALID_EDGE_WEIGHT, "unroutable route");
|
BOOST_ASSERT_MSG(min_route.shortest_path_weight < INVALID_EDGE_WEIGHT, "unroutable route");
|
||||||
return min_route;
|
return min_route;
|
||||||
}
|
}
|
||||||
@ -226,7 +213,7 @@ Status TripPlugin::HandleRequest(const RoutingAlgorithmsInterface &algorithms,
|
|||||||
return Error("InvalidValue", "Invalid source or destination value.", result);
|
return Error("InvalidValue", "Invalid source or destination value.", result);
|
||||||
}
|
}
|
||||||
|
|
||||||
auto snapped_phantoms = SnapPhantomNodes(phantom_node_pairs);
|
auto snapped_phantoms = SnapPhantomNodes(std::move(phantom_node_pairs));
|
||||||
|
|
||||||
BOOST_ASSERT(snapped_phantoms.size() == number_of_locations);
|
BOOST_ASSERT(snapped_phantoms.size() == number_of_locations);
|
||||||
|
|
||||||
|
|||||||
@ -5,12 +5,10 @@
|
|||||||
|
|
||||||
#include "util/for_each_pair.hpp"
|
#include "util/for_each_pair.hpp"
|
||||||
#include "util/integer_range.hpp"
|
#include "util/integer_range.hpp"
|
||||||
#include "util/json_container.hpp"
|
|
||||||
|
|
||||||
#include <cstdlib>
|
#include <cstdlib>
|
||||||
|
|
||||||
#include <algorithm>
|
#include <algorithm>
|
||||||
#include <memory>
|
|
||||||
#include <string>
|
#include <string>
|
||||||
#include <vector>
|
#include <vector>
|
||||||
|
|
||||||
@ -95,19 +93,10 @@ Status ViaRoutePlugin::HandleRequest(const RoutingAlgorithmsInterface &algorithm
|
|||||||
}
|
}
|
||||||
BOOST_ASSERT(phantom_node_pairs.size() == route_parameters.coordinates.size());
|
BOOST_ASSERT(phantom_node_pairs.size() == route_parameters.coordinates.size());
|
||||||
|
|
||||||
auto snapped_phantoms = SnapPhantomNodes(phantom_node_pairs);
|
auto snapped_phantoms = SnapPhantomNodes(std::move(phantom_node_pairs));
|
||||||
|
|
||||||
std::vector<PhantomNodes> start_end_nodes;
|
|
||||||
auto build_phantom_pairs = [&start_end_nodes](const PhantomNode &first_node,
|
|
||||||
const PhantomNode &second_node) {
|
|
||||||
start_end_nodes.push_back(PhantomNodes{first_node, second_node});
|
|
||||||
};
|
|
||||||
util::for_each_pair(snapped_phantoms, build_phantom_pairs);
|
|
||||||
|
|
||||||
api::RouteAPI route_api{facade, route_parameters};
|
api::RouteAPI route_api{facade, route_parameters};
|
||||||
|
|
||||||
InternalManyRoutesResult routes;
|
|
||||||
|
|
||||||
// TODO: in v6 we should remove the boolean and only keep the number parameter.
|
// TODO: in v6 we should remove the boolean and only keep the number parameter.
|
||||||
// For now just force them to be in sync. and keep backwards compatibility.
|
// For now just force them to be in sync. and keep backwards compatibility.
|
||||||
const auto wants_alternatives =
|
const auto wants_alternatives =
|
||||||
@ -115,20 +104,23 @@ Status ViaRoutePlugin::HandleRequest(const RoutingAlgorithmsInterface &algorithm
|
|||||||
(route_parameters.alternatives || route_parameters.number_of_alternatives > 0);
|
(route_parameters.alternatives || route_parameters.number_of_alternatives > 0);
|
||||||
const auto number_of_alternatives = std::max(1u, route_parameters.number_of_alternatives);
|
const auto number_of_alternatives = std::max(1u, route_parameters.number_of_alternatives);
|
||||||
|
|
||||||
|
InternalManyRoutesResult routes;
|
||||||
// Alternatives do not support vias, only direct s,t queries supported
|
// Alternatives do not support vias, only direct s,t queries supported
|
||||||
// See the implementation notes and high-level outline.
|
// See the implementation notes and high-level outline.
|
||||||
// https://github.com/Project-OSRM/osrm-backend/issues/3905
|
// https://github.com/Project-OSRM/osrm-backend/issues/3905
|
||||||
if (1 == start_end_nodes.size() && algorithms.HasAlternativePathSearch() && wants_alternatives)
|
if (2 == snapped_phantoms.size() && algorithms.HasAlternativePathSearch() && wants_alternatives)
|
||||||
{
|
{
|
||||||
routes = algorithms.AlternativePathSearch(start_end_nodes.front(), number_of_alternatives);
|
routes = algorithms.AlternativePathSearch({snapped_phantoms[0], snapped_phantoms[1]},
|
||||||
|
number_of_alternatives);
|
||||||
}
|
}
|
||||||
else if (1 == start_end_nodes.size() && algorithms.HasDirectShortestPathSearch())
|
else if (2 == snapped_phantoms.size() && algorithms.HasDirectShortestPathSearch())
|
||||||
{
|
{
|
||||||
routes = algorithms.DirectShortestPathSearch(start_end_nodes.front());
|
routes = algorithms.DirectShortestPathSearch({snapped_phantoms[0], snapped_phantoms[1]});
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
routes = algorithms.ShortestPathSearch(start_end_nodes, route_parameters.continue_straight);
|
routes =
|
||||||
|
algorithms.ShortestPathSearch(snapped_phantoms, route_parameters.continue_straight);
|
||||||
}
|
}
|
||||||
|
|
||||||
// The post condition for all path searches is we have at least one route in our result.
|
// The post condition for all path searches is we have at least one route in our result.
|
||||||
@ -160,18 +152,29 @@ Status ViaRoutePlugin::HandleRequest(const RoutingAlgorithmsInterface &algorithm
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
route_api.MakeResponse(routes, start_end_nodes, result);
|
route_api.MakeResponse(routes, snapped_phantoms, result);
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
auto first_component_id = snapped_phantoms.front().component.id;
|
const auto all_in_same_component =
|
||||||
auto not_in_same_component = std::any_of(snapped_phantoms.begin(),
|
[](const std::vector<PhantomNodeCandidates> &waypoint_candidates) {
|
||||||
snapped_phantoms.end(),
|
return std::any_of(waypoint_candidates.front().begin(),
|
||||||
[first_component_id](const PhantomNode &node) {
|
waypoint_candidates.front().end(),
|
||||||
return node.component.id != first_component_id;
|
// For each of the first possible phantoms, check if all other
|
||||||
});
|
// positions in the list have a phantom from the same component.
|
||||||
|
[&](const PhantomNode &phantom) {
|
||||||
|
const auto component_id = phantom.component.id;
|
||||||
|
return std::all_of(
|
||||||
|
std::next(waypoint_candidates.begin()),
|
||||||
|
std::end(waypoint_candidates),
|
||||||
|
[component_id](const PhantomNodeCandidates &candidates) {
|
||||||
|
return candidatesHaveComponent(candidates,
|
||||||
|
component_id);
|
||||||
|
});
|
||||||
|
});
|
||||||
|
};
|
||||||
|
|
||||||
if (not_in_same_component)
|
if (!all_in_same_component(snapped_phantoms))
|
||||||
{
|
{
|
||||||
return Error("NoRoute", "Impossible route between points", result);
|
return Error("NoRoute", "Impossible route between points", result);
|
||||||
}
|
}
|
||||||
|
|||||||
@ -190,8 +190,8 @@ void computeWeightAndSharingOfViaPath(SearchEngineData<Algorithm> &engine_workin
|
|||||||
s_v_middle,
|
s_v_middle,
|
||||||
upper_bound_s_v_path_weight,
|
upper_bound_s_v_path_weight,
|
||||||
min_edge_offset,
|
min_edge_offset,
|
||||||
DO_NOT_FORCE_LOOPS,
|
{},
|
||||||
DO_NOT_FORCE_LOOPS);
|
{});
|
||||||
}
|
}
|
||||||
// compute path <v,..,t> by reusing backward search from node t
|
// compute path <v,..,t> by reusing backward search from node t
|
||||||
NodeID v_t_middle = SPECIAL_NODEID;
|
NodeID v_t_middle = SPECIAL_NODEID;
|
||||||
@ -205,8 +205,8 @@ void computeWeightAndSharingOfViaPath(SearchEngineData<Algorithm> &engine_workin
|
|||||||
v_t_middle,
|
v_t_middle,
|
||||||
upper_bound_of_v_t_path_weight,
|
upper_bound_of_v_t_path_weight,
|
||||||
min_edge_offset,
|
min_edge_offset,
|
||||||
DO_NOT_FORCE_LOOPS,
|
{},
|
||||||
DO_NOT_FORCE_LOOPS);
|
{});
|
||||||
}
|
}
|
||||||
*real_weight_of_via_path = upper_bound_s_v_path_weight + upper_bound_of_v_t_path_weight;
|
*real_weight_of_via_path = upper_bound_s_v_path_weight + upper_bound_of_v_t_path_weight;
|
||||||
|
|
||||||
@ -351,8 +351,8 @@ bool viaNodeCandidatePassesTTest(SearchEngineData<Algorithm> &engine_working_dat
|
|||||||
*s_v_middle,
|
*s_v_middle,
|
||||||
upper_bound_s_v_path_weight,
|
upper_bound_s_v_path_weight,
|
||||||
min_edge_offset,
|
min_edge_offset,
|
||||||
DO_NOT_FORCE_LOOPS,
|
{},
|
||||||
DO_NOT_FORCE_LOOPS);
|
{});
|
||||||
}
|
}
|
||||||
|
|
||||||
if (INVALID_EDGE_WEIGHT == upper_bound_s_v_path_weight)
|
if (INVALID_EDGE_WEIGHT == upper_bound_s_v_path_weight)
|
||||||
@ -372,8 +372,8 @@ bool viaNodeCandidatePassesTTest(SearchEngineData<Algorithm> &engine_working_dat
|
|||||||
*v_t_middle,
|
*v_t_middle,
|
||||||
upper_bound_of_v_t_path_weight,
|
upper_bound_of_v_t_path_weight,
|
||||||
min_edge_offset,
|
min_edge_offset,
|
||||||
DO_NOT_FORCE_LOOPS,
|
{},
|
||||||
DO_NOT_FORCE_LOOPS);
|
{});
|
||||||
}
|
}
|
||||||
|
|
||||||
if (INVALID_EDGE_WEIGHT == upper_bound_of_v_t_path_weight)
|
if (INVALID_EDGE_WEIGHT == upper_bound_of_v_t_path_weight)
|
||||||
@ -539,25 +539,13 @@ bool viaNodeCandidatePassesTTest(SearchEngineData<Algorithm> &engine_working_dat
|
|||||||
{
|
{
|
||||||
if (!forward_heap3.Empty())
|
if (!forward_heap3.Empty())
|
||||||
{
|
{
|
||||||
routingStep<FORWARD_DIRECTION>(facade,
|
routingStep<FORWARD_DIRECTION>(
|
||||||
forward_heap3,
|
facade, forward_heap3, reverse_heap3, middle, upper_bound, min_edge_offset, {}, {});
|
||||||
reverse_heap3,
|
|
||||||
middle,
|
|
||||||
upper_bound,
|
|
||||||
min_edge_offset,
|
|
||||||
DO_NOT_FORCE_LOOPS,
|
|
||||||
DO_NOT_FORCE_LOOPS);
|
|
||||||
}
|
}
|
||||||
if (!reverse_heap3.Empty())
|
if (!reverse_heap3.Empty())
|
||||||
{
|
{
|
||||||
routingStep<REVERSE_DIRECTION>(facade,
|
routingStep<REVERSE_DIRECTION>(
|
||||||
reverse_heap3,
|
facade, reverse_heap3, forward_heap3, middle, upper_bound, min_edge_offset, {}, {});
|
||||||
forward_heap3,
|
|
||||||
middle,
|
|
||||||
upper_bound,
|
|
||||||
min_edge_offset,
|
|
||||||
DO_NOT_FORCE_LOOPS,
|
|
||||||
DO_NOT_FORCE_LOOPS);
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
return (upper_bound <= t_test_path_weight);
|
return (upper_bound <= t_test_path_weight);
|
||||||
@ -566,15 +554,12 @@ bool viaNodeCandidatePassesTTest(SearchEngineData<Algorithm> &engine_working_dat
|
|||||||
|
|
||||||
InternalManyRoutesResult alternativePathSearch(SearchEngineData<Algorithm> &engine_working_data,
|
InternalManyRoutesResult alternativePathSearch(SearchEngineData<Algorithm> &engine_working_data,
|
||||||
const DataFacade<Algorithm> &facade,
|
const DataFacade<Algorithm> &facade,
|
||||||
const PhantomNodes &phantom_node_pair,
|
const PhantomEndpointCandidates &endpoint_candidates,
|
||||||
unsigned /*number_of_alternatives*/)
|
unsigned /*number_of_alternatives*/)
|
||||||
{
|
{
|
||||||
InternalRouteResult primary_route;
|
InternalRouteResult primary_route;
|
||||||
InternalRouteResult secondary_route;
|
InternalRouteResult secondary_route;
|
||||||
|
|
||||||
primary_route.segment_end_coordinates = {phantom_node_pair};
|
|
||||||
secondary_route.segment_end_coordinates = {phantom_node_pair};
|
|
||||||
|
|
||||||
std::vector<NodeID> alternative_path;
|
std::vector<NodeID> alternative_path;
|
||||||
std::vector<NodeID> via_node_candidate_list;
|
std::vector<NodeID> via_node_candidate_list;
|
||||||
std::vector<SearchSpaceEdge> forward_search_space;
|
std::vector<SearchSpaceEdge> forward_search_space;
|
||||||
@ -592,15 +577,13 @@ InternalManyRoutesResult alternativePathSearch(SearchEngineData<Algorithm> &engi
|
|||||||
|
|
||||||
EdgeWeight upper_bound_to_shortest_path_weight = INVALID_EDGE_WEIGHT;
|
EdgeWeight upper_bound_to_shortest_path_weight = INVALID_EDGE_WEIGHT;
|
||||||
NodeID middle_node = SPECIAL_NODEID;
|
NodeID middle_node = SPECIAL_NODEID;
|
||||||
const EdgeWeight min_edge_offset =
|
|
||||||
std::min(phantom_node_pair.source_phantom.forward_segment_id.enabled
|
|
||||||
? -phantom_node_pair.source_phantom.GetForwardWeightPlusOffset()
|
|
||||||
: 0,
|
|
||||||
phantom_node_pair.source_phantom.reverse_segment_id.enabled
|
|
||||||
? -phantom_node_pair.source_phantom.GetReverseWeightPlusOffset()
|
|
||||||
: 0);
|
|
||||||
|
|
||||||
insertNodesInHeaps(forward_heap1, reverse_heap1, phantom_node_pair);
|
insertNodesInHeaps(forward_heap1, reverse_heap1, endpoint_candidates);
|
||||||
|
// get offset to account for offsets on phantom nodes on compressed edges
|
||||||
|
EdgeWeight min_edge_offset = forward_heap1.Empty() ? 0 : std::min(0, forward_heap1.MinKey());
|
||||||
|
BOOST_ASSERT(min_edge_offset <= 0);
|
||||||
|
// we only every insert negative offsets for nodes in the forward heap
|
||||||
|
BOOST_ASSERT(reverse_heap1.Empty() || reverse_heap1.MinKey() >= 0);
|
||||||
|
|
||||||
// search from s and t till new_min/(1+epsilon) > weight_of_shortest_path
|
// search from s and t till new_min/(1+epsilon) > weight_of_shortest_path
|
||||||
while (0 < (forward_heap1.Size() + reverse_heap1.Size()))
|
while (0 < (forward_heap1.Size() + reverse_heap1.Size()))
|
||||||
@ -790,7 +773,7 @@ InternalManyRoutesResult alternativePathSearch(SearchEngineData<Algorithm> &engi
|
|||||||
&v_t_middle,
|
&v_t_middle,
|
||||||
min_edge_offset))
|
min_edge_offset))
|
||||||
{
|
{
|
||||||
// select first admissable
|
// select first admissible
|
||||||
selected_via_node = candidate.node;
|
selected_via_node = candidate.node;
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
@ -799,20 +782,23 @@ InternalManyRoutesResult alternativePathSearch(SearchEngineData<Algorithm> &engi
|
|||||||
// Unpack shortest path and alternative, if they exist
|
// Unpack shortest path and alternative, if they exist
|
||||||
if (INVALID_EDGE_WEIGHT != upper_bound_to_shortest_path_weight)
|
if (INVALID_EDGE_WEIGHT != upper_bound_to_shortest_path_weight)
|
||||||
{
|
{
|
||||||
|
auto phantom_endpoints = endpointsFromCandidates(endpoint_candidates, packed_shortest_path);
|
||||||
|
primary_route.leg_endpoints = {phantom_endpoints};
|
||||||
|
|
||||||
BOOST_ASSERT(!packed_shortest_path.empty());
|
BOOST_ASSERT(!packed_shortest_path.empty());
|
||||||
primary_route.unpacked_path_segments.resize(1);
|
primary_route.unpacked_path_segments.resize(1);
|
||||||
primary_route.source_traversed_in_reverse.push_back(
|
primary_route.source_traversed_in_reverse.push_back(
|
||||||
(packed_shortest_path.front() !=
|
(packed_shortest_path.front() !=
|
||||||
phantom_node_pair.source_phantom.forward_segment_id.id));
|
phantom_endpoints.source_phantom.forward_segment_id.id));
|
||||||
primary_route.target_traversed_in_reverse.push_back((
|
primary_route.target_traversed_in_reverse.push_back((
|
||||||
packed_shortest_path.back() != phantom_node_pair.target_phantom.forward_segment_id.id));
|
packed_shortest_path.back() != phantom_endpoints.target_phantom.forward_segment_id.id));
|
||||||
|
|
||||||
unpackPath(facade,
|
unpackPath(facade,
|
||||||
// -- packed input
|
// -- packed input
|
||||||
packed_shortest_path.begin(),
|
packed_shortest_path.begin(),
|
||||||
packed_shortest_path.end(),
|
packed_shortest_path.end(),
|
||||||
// -- start of route
|
// -- start of route
|
||||||
phantom_node_pair,
|
phantom_endpoints,
|
||||||
// -- unpacked output
|
// -- unpacked output
|
||||||
primary_route.unpacked_path_segments.front());
|
primary_route.unpacked_path_segments.front());
|
||||||
primary_route.shortest_path_weight = upper_bound_to_shortest_path_weight;
|
primary_route.shortest_path_weight = upper_bound_to_shortest_path_weight;
|
||||||
@ -830,19 +816,23 @@ InternalManyRoutesResult alternativePathSearch(SearchEngineData<Algorithm> &engi
|
|||||||
v_t_middle,
|
v_t_middle,
|
||||||
packed_alternate_path);
|
packed_alternate_path);
|
||||||
|
|
||||||
|
auto phantom_endpoints =
|
||||||
|
endpointsFromCandidates(endpoint_candidates, packed_alternate_path);
|
||||||
|
secondary_route.leg_endpoints = {phantom_endpoints};
|
||||||
|
|
||||||
secondary_route.unpacked_path_segments.resize(1);
|
secondary_route.unpacked_path_segments.resize(1);
|
||||||
secondary_route.source_traversed_in_reverse.push_back(
|
secondary_route.source_traversed_in_reverse.push_back(
|
||||||
(packed_alternate_path.front() !=
|
(packed_alternate_path.front() !=
|
||||||
phantom_node_pair.source_phantom.forward_segment_id.id));
|
phantom_endpoints.source_phantom.forward_segment_id.id));
|
||||||
secondary_route.target_traversed_in_reverse.push_back(
|
secondary_route.target_traversed_in_reverse.push_back(
|
||||||
(packed_alternate_path.back() !=
|
(packed_alternate_path.back() !=
|
||||||
phantom_node_pair.target_phantom.forward_segment_id.id));
|
phantom_endpoints.target_phantom.forward_segment_id.id));
|
||||||
|
|
||||||
// unpack the alternate path
|
// unpack the alternate path
|
||||||
unpackPath(facade,
|
unpackPath(facade,
|
||||||
packed_alternate_path.begin(),
|
packed_alternate_path.begin(),
|
||||||
packed_alternate_path.end(),
|
packed_alternate_path.end(),
|
||||||
phantom_node_pair,
|
phantom_endpoints,
|
||||||
secondary_route.unpacked_path_segments.front());
|
secondary_route.unpacked_path_segments.front());
|
||||||
|
|
||||||
secondary_route.shortest_path_weight = weight_of_via_path;
|
secondary_route.shortest_path_weight = weight_of_via_path;
|
||||||
|
|||||||
@ -133,12 +133,13 @@ double getLongerByFactorBasedOnDuration(const EdgeWeight duration)
|
|||||||
return a + b / (duration - d) + c / std::pow(duration - d, 3);
|
return a + b / (duration - d) + c / std::pow(duration - d, 3);
|
||||||
}
|
}
|
||||||
|
|
||||||
Parameters parametersFromRequest(const PhantomNodes &phantom_node_pair)
|
Parameters parametersFromRequest(const PhantomEndpointCandidates &endpoint_candidates)
|
||||||
{
|
{
|
||||||
Parameters parameters;
|
Parameters parameters;
|
||||||
|
|
||||||
const auto distance = util::coordinate_calculation::greatCircleDistance(
|
const auto distance = util::coordinate_calculation::greatCircleDistance(
|
||||||
phantom_node_pair.source_phantom.location, phantom_node_pair.target_phantom.location);
|
candidatesSnappedLocation(endpoint_candidates.source_phantoms),
|
||||||
|
candidatesSnappedLocation(endpoint_candidates.target_phantoms));
|
||||||
|
|
||||||
// 10km
|
// 10km
|
||||||
if (distance < 10000.)
|
if (distance < 10000.)
|
||||||
@ -547,7 +548,7 @@ void unpackPackedPaths(InputIt first,
|
|||||||
OutIt out,
|
OutIt out,
|
||||||
SearchEngineData<Algorithm> &search_engine_data,
|
SearchEngineData<Algorithm> &search_engine_data,
|
||||||
const Facade &facade,
|
const Facade &facade,
|
||||||
const PhantomNodes &phantom_node_pair)
|
const PhantomEndpointCandidates &endpoint_candidates)
|
||||||
{
|
{
|
||||||
util::static_assert_iter_category<InputIt, std::input_iterator_tag>();
|
util::static_assert_iter_category<InputIt, std::input_iterator_tag>();
|
||||||
util::static_assert_iter_category<OutIt, std::output_iterator_tag>();
|
util::static_assert_iter_category<OutIt, std::output_iterator_tag>();
|
||||||
@ -600,7 +601,7 @@ void unpackPackedPaths(InputIt first,
|
|||||||
}
|
}
|
||||||
else
|
else
|
||||||
{ // an overlay graph edge
|
{ // an overlay graph edge
|
||||||
LevelID level = getNodeQueryLevel(partition, source, phantom_node_pair); // XXX
|
LevelID level = getNodeQueryLevel(partition, source, endpoint_candidates); // XXX
|
||||||
CellID parent_cell_id = partition.GetCell(level, source);
|
CellID parent_cell_id = partition.GetCell(level, source);
|
||||||
BOOST_ASSERT(parent_cell_id == partition.GetCell(level, target));
|
BOOST_ASSERT(parent_cell_id == partition.GetCell(level, target));
|
||||||
|
|
||||||
@ -624,8 +625,8 @@ void unpackPackedPaths(InputIt first,
|
|||||||
facade,
|
facade,
|
||||||
forward_heap,
|
forward_heap,
|
||||||
reverse_heap,
|
reverse_heap,
|
||||||
DO_NOT_FORCE_LOOPS,
|
{},
|
||||||
DO_NOT_FORCE_LOOPS,
|
{},
|
||||||
INVALID_EDGE_WEIGHT,
|
INVALID_EDGE_WEIGHT,
|
||||||
sublevel,
|
sublevel,
|
||||||
parent_cell_id);
|
parent_cell_id);
|
||||||
@ -656,13 +657,13 @@ void unpackPackedPaths(InputIt first,
|
|||||||
inline std::vector<WeightedViaNode>
|
inline std::vector<WeightedViaNode>
|
||||||
makeCandidateVias(SearchEngineData<Algorithm> &search_engine_data,
|
makeCandidateVias(SearchEngineData<Algorithm> &search_engine_data,
|
||||||
const Facade &facade,
|
const Facade &facade,
|
||||||
const PhantomNodes &phantom_node_pair,
|
const PhantomEndpointCandidates &endpoint_candidates,
|
||||||
const Parameters ¶meters)
|
const Parameters ¶meters)
|
||||||
{
|
{
|
||||||
Heap &forward_heap = *search_engine_data.forward_heap_1;
|
Heap &forward_heap = *search_engine_data.forward_heap_1;
|
||||||
Heap &reverse_heap = *search_engine_data.reverse_heap_1;
|
Heap &reverse_heap = *search_engine_data.reverse_heap_1;
|
||||||
|
|
||||||
insertNodesInHeaps(forward_heap, reverse_heap, phantom_node_pair);
|
insertNodesInHeaps(forward_heap, reverse_heap, endpoint_candidates);
|
||||||
if (forward_heap.Empty() || reverse_heap.Empty())
|
if (forward_heap.Empty() || reverse_heap.Empty())
|
||||||
{
|
{
|
||||||
return {};
|
return {};
|
||||||
@ -712,9 +713,9 @@ makeCandidateVias(SearchEngineData<Algorithm> &search_engine_data,
|
|||||||
reverse_heap,
|
reverse_heap,
|
||||||
overlap_via,
|
overlap_via,
|
||||||
overlap_weight,
|
overlap_weight,
|
||||||
DO_NOT_FORCE_LOOPS,
|
{},
|
||||||
DO_NOT_FORCE_LOOPS,
|
{},
|
||||||
phantom_node_pair);
|
endpoint_candidates);
|
||||||
|
|
||||||
if (!forward_heap.Empty())
|
if (!forward_heap.Empty())
|
||||||
forward_heap_min = forward_heap.MinKey();
|
forward_heap_min = forward_heap.MinKey();
|
||||||
@ -738,9 +739,9 @@ makeCandidateVias(SearchEngineData<Algorithm> &search_engine_data,
|
|||||||
forward_heap,
|
forward_heap,
|
||||||
overlap_via,
|
overlap_via,
|
||||||
overlap_weight,
|
overlap_weight,
|
||||||
DO_NOT_FORCE_LOOPS,
|
{},
|
||||||
DO_NOT_FORCE_LOOPS,
|
{},
|
||||||
phantom_node_pair);
|
endpoint_candidates);
|
||||||
|
|
||||||
if (!reverse_heap.Empty())
|
if (!reverse_heap.Empty())
|
||||||
reverse_heap_min = reverse_heap.MinKey();
|
reverse_heap_min = reverse_heap.MinKey();
|
||||||
@ -776,10 +777,10 @@ makeCandidateVias(SearchEngineData<Algorithm> &search_engine_data,
|
|||||||
// https://github.com/Project-OSRM/osrm-backend/issues/3905
|
// https://github.com/Project-OSRM/osrm-backend/issues/3905
|
||||||
InternalManyRoutesResult alternativePathSearch(SearchEngineData<Algorithm> &search_engine_data,
|
InternalManyRoutesResult alternativePathSearch(SearchEngineData<Algorithm> &search_engine_data,
|
||||||
const Facade &facade,
|
const Facade &facade,
|
||||||
const PhantomNodes &phantom_node_pair,
|
const PhantomEndpointCandidates &endpoint_candidates,
|
||||||
unsigned number_of_alternatives)
|
unsigned number_of_alternatives)
|
||||||
{
|
{
|
||||||
Parameters parameters = parametersFromRequest(phantom_node_pair);
|
Parameters parameters = parametersFromRequest(endpoint_candidates);
|
||||||
|
|
||||||
const auto max_number_of_alternatives = number_of_alternatives;
|
const auto max_number_of_alternatives = number_of_alternatives;
|
||||||
const auto max_number_of_alternatives_to_unpack =
|
const auto max_number_of_alternatives_to_unpack =
|
||||||
@ -798,7 +799,7 @@ InternalManyRoutesResult alternativePathSearch(SearchEngineData<Algorithm> &sear
|
|||||||
|
|
||||||
// Do forward and backward search, save search space overlap as via candidates.
|
// Do forward and backward search, save search space overlap as via candidates.
|
||||||
auto candidate_vias =
|
auto candidate_vias =
|
||||||
makeCandidateVias(search_engine_data, facade, phantom_node_pair, parameters);
|
makeCandidateVias(search_engine_data, facade, endpoint_candidates, parameters);
|
||||||
|
|
||||||
const auto by_weight = [](const auto &lhs, const auto &rhs) { return lhs.weight < rhs.weight; };
|
const auto by_weight = [](const auto &lhs, const auto &rhs) { return lhs.weight < rhs.weight; };
|
||||||
auto shortest_path_via_it =
|
auto shortest_path_via_it =
|
||||||
@ -813,8 +814,6 @@ InternalManyRoutesResult alternativePathSearch(SearchEngineData<Algorithm> &sear
|
|||||||
if (!has_shortest_path)
|
if (!has_shortest_path)
|
||||||
{
|
{
|
||||||
InternalRouteResult invalid;
|
InternalRouteResult invalid;
|
||||||
invalid.shortest_path_weight = INVALID_EDGE_WEIGHT;
|
|
||||||
invalid.segment_end_coordinates = {phantom_node_pair};
|
|
||||||
return invalid;
|
return invalid;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -900,7 +899,7 @@ InternalManyRoutesResult alternativePathSearch(SearchEngineData<Algorithm> &sear
|
|||||||
std::back_inserter(unpacked_paths),
|
std::back_inserter(unpacked_paths),
|
||||||
search_engine_data,
|
search_engine_data,
|
||||||
facade,
|
facade,
|
||||||
phantom_node_pair);
|
endpoint_candidates);
|
||||||
|
|
||||||
//
|
//
|
||||||
// Filter and rank a second time. This time instead of being fast and doing
|
// Filter and rank a second time. This time instead of being fast and doing
|
||||||
@ -927,7 +926,7 @@ InternalManyRoutesResult alternativePathSearch(SearchEngineData<Algorithm> &sear
|
|||||||
routes.reserve(number_of_unpacked_paths);
|
routes.reserve(number_of_unpacked_paths);
|
||||||
|
|
||||||
const auto unpacked_path_to_route = [&](const WeightedViaNodeUnpackedPath &path) {
|
const auto unpacked_path_to_route = [&](const WeightedViaNodeUnpackedPath &path) {
|
||||||
return extractRoute(facade, path.via.weight, phantom_node_pair, path.nodes, path.edges);
|
return extractRoute(facade, path.via.weight, endpoint_candidates, path.nodes, path.edges);
|
||||||
};
|
};
|
||||||
|
|
||||||
std::transform(unpacked_paths_first,
|
std::transform(unpacked_paths_first,
|
||||||
|
|||||||
@ -19,7 +19,7 @@ namespace routing_algorithms
|
|||||||
template <>
|
template <>
|
||||||
InternalRouteResult directShortestPathSearch(SearchEngineData<ch::Algorithm> &engine_working_data,
|
InternalRouteResult directShortestPathSearch(SearchEngineData<ch::Algorithm> &engine_working_data,
|
||||||
const DataFacade<ch::Algorithm> &facade,
|
const DataFacade<ch::Algorithm> &facade,
|
||||||
const PhantomNodes &phantom_nodes)
|
const PhantomEndpointCandidates &endpoint_candidates)
|
||||||
{
|
{
|
||||||
engine_working_data.InitializeOrClearFirstThreadLocalStorage(facade.GetNumberOfNodes());
|
engine_working_data.InitializeOrClearFirstThreadLocalStorage(facade.GetNumberOfNodes());
|
||||||
auto &forward_heap = *engine_working_data.forward_heap_1;
|
auto &forward_heap = *engine_working_data.forward_heap_1;
|
||||||
@ -29,7 +29,7 @@ InternalRouteResult directShortestPathSearch(SearchEngineData<ch::Algorithm> &en
|
|||||||
|
|
||||||
EdgeWeight weight = INVALID_EDGE_WEIGHT;
|
EdgeWeight weight = INVALID_EDGE_WEIGHT;
|
||||||
std::vector<NodeID> packed_leg;
|
std::vector<NodeID> packed_leg;
|
||||||
insertNodesInHeaps(forward_heap, reverse_heap, phantom_nodes);
|
insertNodesInHeaps(forward_heap, reverse_heap, endpoint_candidates);
|
||||||
|
|
||||||
search(engine_working_data,
|
search(engine_working_data,
|
||||||
facade,
|
facade,
|
||||||
@ -37,9 +37,9 @@ InternalRouteResult directShortestPathSearch(SearchEngineData<ch::Algorithm> &en
|
|||||||
reverse_heap,
|
reverse_heap,
|
||||||
weight,
|
weight,
|
||||||
packed_leg,
|
packed_leg,
|
||||||
DO_NOT_FORCE_LOOPS,
|
{},
|
||||||
DO_NOT_FORCE_LOOPS,
|
{},
|
||||||
phantom_nodes);
|
endpoint_candidates);
|
||||||
|
|
||||||
std::vector<NodeID> unpacked_nodes;
|
std::vector<NodeID> unpacked_nodes;
|
||||||
std::vector<EdgeID> unpacked_edges;
|
std::vector<EdgeID> unpacked_edges;
|
||||||
@ -60,19 +60,19 @@ InternalRouteResult directShortestPathSearch(SearchEngineData<ch::Algorithm> &en
|
|||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
return extractRoute(facade, weight, phantom_nodes, unpacked_nodes, unpacked_edges);
|
return extractRoute(facade, weight, endpoint_candidates, unpacked_nodes, unpacked_edges);
|
||||||
}
|
}
|
||||||
|
|
||||||
template <>
|
template <>
|
||||||
InternalRouteResult directShortestPathSearch(SearchEngineData<mld::Algorithm> &engine_working_data,
|
InternalRouteResult directShortestPathSearch(SearchEngineData<mld::Algorithm> &engine_working_data,
|
||||||
const DataFacade<mld::Algorithm> &facade,
|
const DataFacade<mld::Algorithm> &facade,
|
||||||
const PhantomNodes &phantom_nodes)
|
const PhantomEndpointCandidates &endpoint_candidates)
|
||||||
{
|
{
|
||||||
engine_working_data.InitializeOrClearFirstThreadLocalStorage(facade.GetNumberOfNodes(),
|
engine_working_data.InitializeOrClearFirstThreadLocalStorage(facade.GetNumberOfNodes(),
|
||||||
facade.GetMaxBorderNodeID() + 1);
|
facade.GetMaxBorderNodeID() + 1);
|
||||||
auto &forward_heap = *engine_working_data.forward_heap_1;
|
auto &forward_heap = *engine_working_data.forward_heap_1;
|
||||||
auto &reverse_heap = *engine_working_data.reverse_heap_1;
|
auto &reverse_heap = *engine_working_data.reverse_heap_1;
|
||||||
insertNodesInHeaps(forward_heap, reverse_heap, phantom_nodes);
|
insertNodesInHeaps(forward_heap, reverse_heap, endpoint_candidates);
|
||||||
|
|
||||||
// TODO: when structured bindings will be allowed change to
|
// TODO: when structured bindings will be allowed change to
|
||||||
// auto [weight, source_node, target_node, unpacked_edges] = ...
|
// auto [weight, source_node, target_node, unpacked_edges] = ...
|
||||||
@ -83,12 +83,12 @@ InternalRouteResult directShortestPathSearch(SearchEngineData<mld::Algorithm> &e
|
|||||||
facade,
|
facade,
|
||||||
forward_heap,
|
forward_heap,
|
||||||
reverse_heap,
|
reverse_heap,
|
||||||
DO_NOT_FORCE_LOOPS,
|
{},
|
||||||
DO_NOT_FORCE_LOOPS,
|
{},
|
||||||
INVALID_EDGE_WEIGHT,
|
INVALID_EDGE_WEIGHT,
|
||||||
phantom_nodes);
|
endpoint_candidates);
|
||||||
|
|
||||||
return extractRoute(facade, weight, phantom_nodes, unpacked_nodes, unpacked_edges);
|
return extractRoute(facade, weight, endpoint_candidates, unpacked_nodes, unpacked_edges);
|
||||||
}
|
}
|
||||||
|
|
||||||
} // namespace routing_algorithms
|
} // namespace routing_algorithms
|
||||||
|
|||||||
@ -49,7 +49,7 @@ void relaxOutgoingEdges(
|
|||||||
const DataFacade<Algorithm> &facade,
|
const DataFacade<Algorithm> &facade,
|
||||||
const typename SearchEngineData<Algorithm>::ManyToManyQueryHeap::HeapNode &heapNode,
|
const typename SearchEngineData<Algorithm>::ManyToManyQueryHeap::HeapNode &heapNode,
|
||||||
typename SearchEngineData<Algorithm>::ManyToManyQueryHeap &query_heap,
|
typename SearchEngineData<Algorithm>::ManyToManyQueryHeap &query_heap,
|
||||||
const PhantomNode &)
|
const PhantomNodeCandidates &)
|
||||||
{
|
{
|
||||||
if (stallAtNode<DIRECTION>(facade, heapNode, query_heap))
|
if (stallAtNode<DIRECTION>(facade, heapNode, query_heap))
|
||||||
{
|
{
|
||||||
@ -99,7 +99,7 @@ void forwardRoutingStep(const DataFacade<Algorithm> &facade,
|
|||||||
std::vector<EdgeDuration> &durations_table,
|
std::vector<EdgeDuration> &durations_table,
|
||||||
std::vector<EdgeDistance> &distances_table,
|
std::vector<EdgeDistance> &distances_table,
|
||||||
std::vector<NodeID> &middle_nodes_table,
|
std::vector<NodeID> &middle_nodes_table,
|
||||||
const PhantomNode &phantom_node)
|
const PhantomNodeCandidates &candidates)
|
||||||
{
|
{
|
||||||
// Take a copy of the extracted node because otherwise could be modified later if toHeapNode is
|
// Take a copy of the extracted node because otherwise could be modified later if toHeapNode is
|
||||||
// the same
|
// the same
|
||||||
@ -151,14 +151,14 @@ void forwardRoutingStep(const DataFacade<Algorithm> &facade,
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
relaxOutgoingEdges<FORWARD_DIRECTION>(facade, heapNode, query_heap, phantom_node);
|
relaxOutgoingEdges<FORWARD_DIRECTION>(facade, heapNode, query_heap, candidates);
|
||||||
}
|
}
|
||||||
|
|
||||||
void backwardRoutingStep(const DataFacade<Algorithm> &facade,
|
void backwardRoutingStep(const DataFacade<Algorithm> &facade,
|
||||||
const unsigned column_index,
|
const unsigned column_index,
|
||||||
typename SearchEngineData<Algorithm>::ManyToManyQueryHeap &query_heap,
|
typename SearchEngineData<Algorithm>::ManyToManyQueryHeap &query_heap,
|
||||||
std::vector<NodeBucket> &search_space_with_buckets,
|
std::vector<NodeBucket> &search_space_with_buckets,
|
||||||
const PhantomNode &phantom_node)
|
const PhantomNodeCandidates &candidates)
|
||||||
{
|
{
|
||||||
// Take a copy (no ref &) of the extracted node because otherwise could be modified later if
|
// Take a copy (no ref &) of the extracted node because otherwise could be modified later if
|
||||||
// toHeapNode is the same
|
// toHeapNode is the same
|
||||||
@ -172,7 +172,7 @@ void backwardRoutingStep(const DataFacade<Algorithm> &facade,
|
|||||||
heapNode.data.duration,
|
heapNode.data.duration,
|
||||||
heapNode.data.distance);
|
heapNode.data.distance);
|
||||||
|
|
||||||
relaxOutgoingEdges<REVERSE_DIRECTION>(facade, heapNode, query_heap, phantom_node);
|
relaxOutgoingEdges<REVERSE_DIRECTION>(facade, heapNode, query_heap, candidates);
|
||||||
}
|
}
|
||||||
|
|
||||||
} // namespace ch
|
} // namespace ch
|
||||||
@ -181,7 +181,7 @@ template <>
|
|||||||
std::pair<std::vector<EdgeDuration>, std::vector<EdgeDistance>>
|
std::pair<std::vector<EdgeDuration>, std::vector<EdgeDistance>>
|
||||||
manyToManySearch(SearchEngineData<ch::Algorithm> &engine_working_data,
|
manyToManySearch(SearchEngineData<ch::Algorithm> &engine_working_data,
|
||||||
const DataFacade<ch::Algorithm> &facade,
|
const DataFacade<ch::Algorithm> &facade,
|
||||||
const std::vector<PhantomNode> &phantom_nodes,
|
const std::vector<PhantomNodeCandidates> &candidates_list,
|
||||||
const std::vector<std::size_t> &source_indices,
|
const std::vector<std::size_t> &source_indices,
|
||||||
const std::vector<std::size_t> &target_indices,
|
const std::vector<std::size_t> &target_indices,
|
||||||
const bool calculate_distance)
|
const bool calculate_distance)
|
||||||
@ -202,18 +202,18 @@ manyToManySearch(SearchEngineData<ch::Algorithm> &engine_working_data,
|
|||||||
for (std::uint32_t column_index = 0; column_index < target_indices.size(); ++column_index)
|
for (std::uint32_t column_index = 0; column_index < target_indices.size(); ++column_index)
|
||||||
{
|
{
|
||||||
const auto index = target_indices[column_index];
|
const auto index = target_indices[column_index];
|
||||||
const auto &phantom = phantom_nodes[index];
|
const auto &target_candidates = candidates_list[index];
|
||||||
|
|
||||||
engine_working_data.InitializeOrClearManyToManyThreadLocalStorage(
|
engine_working_data.InitializeOrClearManyToManyThreadLocalStorage(
|
||||||
facade.GetNumberOfNodes());
|
facade.GetNumberOfNodes());
|
||||||
auto &query_heap = *(engine_working_data.many_to_many_heap);
|
auto &query_heap = *(engine_working_data.many_to_many_heap);
|
||||||
insertTargetInHeap(query_heap, phantom);
|
insertTargetInHeap(query_heap, target_candidates);
|
||||||
|
|
||||||
// Explore search space
|
// Explore search space
|
||||||
while (!query_heap.Empty())
|
while (!query_heap.Empty())
|
||||||
{
|
{
|
||||||
backwardRoutingStep(
|
backwardRoutingStep(
|
||||||
facade, column_index, query_heap, search_space_with_buckets, phantom);
|
facade, column_index, query_heap, search_space_with_buckets, target_candidates);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -224,13 +224,13 @@ manyToManySearch(SearchEngineData<ch::Algorithm> &engine_working_data,
|
|||||||
for (std::uint32_t row_index = 0; row_index < source_indices.size(); ++row_index)
|
for (std::uint32_t row_index = 0; row_index < source_indices.size(); ++row_index)
|
||||||
{
|
{
|
||||||
const auto source_index = source_indices[row_index];
|
const auto source_index = source_indices[row_index];
|
||||||
const auto &source_phantom = phantom_nodes[source_index];
|
const auto &source_candidates = candidates_list[source_index];
|
||||||
|
|
||||||
// Clear heap and insert source nodes
|
// Clear heap and insert source nodes
|
||||||
engine_working_data.InitializeOrClearManyToManyThreadLocalStorage(
|
engine_working_data.InitializeOrClearManyToManyThreadLocalStorage(
|
||||||
facade.GetNumberOfNodes());
|
facade.GetNumberOfNodes());
|
||||||
auto &query_heap = *(engine_working_data.many_to_many_heap);
|
auto &query_heap = *(engine_working_data.many_to_many_heap);
|
||||||
insertSourceInHeap(query_heap, source_phantom);
|
insertSourceInHeap(query_heap, source_candidates);
|
||||||
|
|
||||||
// Explore search space
|
// Explore search space
|
||||||
while (!query_heap.Empty())
|
while (!query_heap.Empty())
|
||||||
@ -244,7 +244,7 @@ manyToManySearch(SearchEngineData<ch::Algorithm> &engine_working_data,
|
|||||||
durations_table,
|
durations_table,
|
||||||
distances_table,
|
distances_table,
|
||||||
middle_nodes_table,
|
middle_nodes_table,
|
||||||
source_phantom);
|
source_candidates);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@ -25,7 +25,7 @@ using PackedPath = std::vector<PackedEdge>;
|
|||||||
template <typename MultiLevelPartition>
|
template <typename MultiLevelPartition>
|
||||||
inline LevelID getNodeQueryLevel(const MultiLevelPartition &partition,
|
inline LevelID getNodeQueryLevel(const MultiLevelPartition &partition,
|
||||||
const NodeID node,
|
const NodeID node,
|
||||||
const PhantomNode &phantom_node,
|
const PhantomNodeCandidates &phantom_node,
|
||||||
const LevelID maximal_level)
|
const LevelID maximal_level)
|
||||||
{
|
{
|
||||||
const auto node_level = getNodeQueryLevel(partition, node, phantom_node);
|
const auto node_level = getNodeQueryLevel(partition, node, phantom_node);
|
||||||
@ -96,7 +96,7 @@ void relaxOutgoingEdges(
|
|||||||
const DataFacade<mld::Algorithm> &facade,
|
const DataFacade<mld::Algorithm> &facade,
|
||||||
const typename SearchEngineData<mld::Algorithm>::ManyToManyQueryHeap::HeapNode &heapNode,
|
const typename SearchEngineData<mld::Algorithm>::ManyToManyQueryHeap::HeapNode &heapNode,
|
||||||
typename SearchEngineData<mld::Algorithm>::ManyToManyQueryHeap &query_heap,
|
typename SearchEngineData<mld::Algorithm>::ManyToManyQueryHeap &query_heap,
|
||||||
Args... args)
|
const Args &... args)
|
||||||
{
|
{
|
||||||
BOOST_ASSERT(!facade.ExcludeNode(heapNode.node));
|
BOOST_ASSERT(!facade.ExcludeNode(heapNode.node));
|
||||||
|
|
||||||
@ -214,59 +214,63 @@ template <bool DIRECTION>
|
|||||||
std::pair<std::vector<EdgeDuration>, std::vector<EdgeDistance>>
|
std::pair<std::vector<EdgeDuration>, std::vector<EdgeDistance>>
|
||||||
oneToManySearch(SearchEngineData<Algorithm> &engine_working_data,
|
oneToManySearch(SearchEngineData<Algorithm> &engine_working_data,
|
||||||
const DataFacade<Algorithm> &facade,
|
const DataFacade<Algorithm> &facade,
|
||||||
const std::vector<PhantomNode> &phantom_nodes,
|
const std::vector<PhantomNodeCandidates> &candidates_list,
|
||||||
std::size_t phantom_index,
|
std::size_t source_index,
|
||||||
const std::vector<std::size_t> &phantom_indices,
|
const std::vector<std::size_t> &target_indices,
|
||||||
const bool calculate_distance)
|
const bool calculate_distance)
|
||||||
{
|
{
|
||||||
std::vector<EdgeWeight> weights_table(phantom_indices.size(), INVALID_EDGE_WEIGHT);
|
std::vector<EdgeWeight> weights_table(target_indices.size(), INVALID_EDGE_WEIGHT);
|
||||||
std::vector<EdgeDuration> durations_table(phantom_indices.size(), MAXIMAL_EDGE_DURATION);
|
std::vector<EdgeDuration> durations_table(target_indices.size(), MAXIMAL_EDGE_DURATION);
|
||||||
std::vector<EdgeDistance> distances_table(calculate_distance ? phantom_indices.size() : 0,
|
std::vector<EdgeDistance> distances_table(calculate_distance ? target_indices.size() : 0,
|
||||||
MAXIMAL_EDGE_DISTANCE);
|
MAXIMAL_EDGE_DISTANCE);
|
||||||
std::vector<NodeID> middle_nodes_table(phantom_indices.size(), SPECIAL_NODEID);
|
std::vector<NodeID> middle_nodes_table(target_indices.size(), SPECIAL_NODEID);
|
||||||
|
|
||||||
// Collect destination (source) nodes into a map
|
// Collect destination (source) nodes into a map
|
||||||
std::unordered_multimap<NodeID, std::tuple<std::size_t, EdgeWeight, EdgeDuration, EdgeDistance>>
|
std::unordered_multimap<NodeID, std::tuple<std::size_t, EdgeWeight, EdgeDuration, EdgeDistance>>
|
||||||
target_nodes_index;
|
target_nodes_index;
|
||||||
target_nodes_index.reserve(phantom_indices.size());
|
target_nodes_index.reserve(target_indices.size());
|
||||||
for (std::size_t index = 0; index < phantom_indices.size(); ++index)
|
for (std::size_t index = 0; index < target_indices.size(); ++index)
|
||||||
{
|
{
|
||||||
const auto &phantom_index = phantom_indices[index];
|
const auto &target_candidates = candidates_list[target_indices[index]];
|
||||||
const auto &phantom_node = phantom_nodes[phantom_index];
|
|
||||||
|
|
||||||
if (DIRECTION == FORWARD_DIRECTION)
|
for (const auto &phantom_node : target_candidates)
|
||||||
{
|
{
|
||||||
if (phantom_node.IsValidForwardTarget())
|
if (DIRECTION == FORWARD_DIRECTION)
|
||||||
target_nodes_index.insert(
|
{
|
||||||
{phantom_node.forward_segment_id.id,
|
if (phantom_node.IsValidForwardTarget())
|
||||||
std::make_tuple(index,
|
target_nodes_index.insert(
|
||||||
phantom_node.GetForwardWeightPlusOffset(),
|
{phantom_node.forward_segment_id.id,
|
||||||
phantom_node.GetForwardDuration(),
|
std::make_tuple(index,
|
||||||
phantom_node.GetForwardDistance())});
|
phantom_node.GetForwardWeightPlusOffset(),
|
||||||
if (phantom_node.IsValidReverseTarget())
|
phantom_node.GetForwardDuration(),
|
||||||
target_nodes_index.insert(
|
phantom_node.GetForwardDistance())});
|
||||||
{phantom_node.reverse_segment_id.id,
|
|
||||||
std::make_tuple(index,
|
if (phantom_node.IsValidReverseTarget())
|
||||||
phantom_node.GetReverseWeightPlusOffset(),
|
target_nodes_index.insert(
|
||||||
phantom_node.GetReverseDuration(),
|
{phantom_node.reverse_segment_id.id,
|
||||||
phantom_node.GetReverseDistance())});
|
std::make_tuple(index,
|
||||||
}
|
phantom_node.GetReverseWeightPlusOffset(),
|
||||||
else if (DIRECTION == REVERSE_DIRECTION)
|
phantom_node.GetReverseDuration(),
|
||||||
{
|
phantom_node.GetReverseDistance())});
|
||||||
if (phantom_node.IsValidForwardSource())
|
}
|
||||||
target_nodes_index.insert(
|
else if (DIRECTION == REVERSE_DIRECTION)
|
||||||
{phantom_node.forward_segment_id.id,
|
{
|
||||||
std::make_tuple(index,
|
if (phantom_node.IsValidForwardSource())
|
||||||
-phantom_node.GetForwardWeightPlusOffset(),
|
target_nodes_index.insert(
|
||||||
-phantom_node.GetForwardDuration(),
|
{phantom_node.forward_segment_id.id,
|
||||||
-phantom_node.GetForwardDistance())});
|
std::make_tuple(index,
|
||||||
if (phantom_node.IsValidReverseSource())
|
-phantom_node.GetForwardWeightPlusOffset(),
|
||||||
target_nodes_index.insert(
|
-phantom_node.GetForwardDuration(),
|
||||||
{phantom_node.reverse_segment_id.id,
|
-phantom_node.GetForwardDistance())});
|
||||||
std::make_tuple(index,
|
|
||||||
-phantom_node.GetReverseWeightPlusOffset(),
|
if (phantom_node.IsValidReverseSource())
|
||||||
-phantom_node.GetReverseDuration(),
|
target_nodes_index.insert(
|
||||||
-phantom_node.GetReverseDistance())});
|
{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
|
{ // 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,
|
if (phantom_node.IsValidForwardSource())
|
||||||
-phantom_node.GetForwardWeightPlusOffset(),
|
{
|
||||||
-phantom_node.GetForwardDuration(),
|
insert_node(phantom_node.forward_segment_id.id,
|
||||||
-phantom_node.GetForwardDistance());
|
-phantom_node.GetForwardWeightPlusOffset(),
|
||||||
}
|
-phantom_node.GetForwardDuration(),
|
||||||
|
-phantom_node.GetForwardDistance());
|
||||||
|
}
|
||||||
|
|
||||||
if (phantom_node.IsValidReverseSource())
|
if (phantom_node.IsValidReverseSource())
|
||||||
{
|
{
|
||||||
insert_node(phantom_node.reverse_segment_id.id,
|
insert_node(phantom_node.reverse_segment_id.id,
|
||||||
-phantom_node.GetReverseWeightPlusOffset(),
|
-phantom_node.GetReverseWeightPlusOffset(),
|
||||||
-phantom_node.GetReverseDuration(),
|
-phantom_node.GetReverseDuration(),
|
||||||
-phantom_node.GetReverseDistance());
|
-phantom_node.GetReverseDistance());
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
else if (DIRECTION == REVERSE_DIRECTION)
|
||||||
else if (DIRECTION == REVERSE_DIRECTION)
|
|
||||||
{
|
|
||||||
if (phantom_node.IsValidForwardTarget())
|
|
||||||
{
|
{
|
||||||
insert_node(phantom_node.forward_segment_id.id,
|
if (phantom_node.IsValidForwardTarget())
|
||||||
phantom_node.GetForwardWeightPlusOffset(),
|
{
|
||||||
phantom_node.GetForwardDuration(),
|
insert_node(phantom_node.forward_segment_id.id,
|
||||||
phantom_node.GetForwardDistance());
|
phantom_node.GetForwardWeightPlusOffset(),
|
||||||
}
|
phantom_node.GetForwardDuration(),
|
||||||
|
phantom_node.GetForwardDistance());
|
||||||
|
}
|
||||||
|
|
||||||
if (phantom_node.IsValidReverseTarget())
|
if (phantom_node.IsValidReverseTarget())
|
||||||
{
|
{
|
||||||
insert_node(phantom_node.reverse_segment_id.id,
|
insert_node(phantom_node.reverse_segment_id.id,
|
||||||
phantom_node.GetReverseWeightPlusOffset(),
|
phantom_node.GetReverseWeightPlusOffset(),
|
||||||
phantom_node.GetReverseDuration(),
|
phantom_node.GetReverseDuration(),
|
||||||
phantom_node.GetReverseDistance());
|
phantom_node.GetReverseDistance());
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -389,7 +396,7 @@ oneToManySearch(SearchEngineData<Algorithm> &engine_working_data,
|
|||||||
|
|
||||||
// Relax outgoing edges
|
// Relax outgoing edges
|
||||||
relaxOutgoingEdges<DIRECTION>(
|
relaxOutgoingEdges<DIRECTION>(
|
||||||
facade, heapNode, query_heap, phantom_nodes, phantom_index, phantom_indices);
|
facade, heapNode, query_heap, candidates_list, source_index, target_indices);
|
||||||
}
|
}
|
||||||
|
|
||||||
return std::make_pair(std::move(durations_table), std::move(distances_table));
|
return std::make_pair(std::move(durations_table), std::move(distances_table));
|
||||||
@ -409,7 +416,7 @@ void forwardRoutingStep(const DataFacade<Algorithm> &facade,
|
|||||||
std::vector<EdgeDuration> &durations_table,
|
std::vector<EdgeDuration> &durations_table,
|
||||||
std::vector<EdgeDistance> &distances_table,
|
std::vector<EdgeDistance> &distances_table,
|
||||||
std::vector<NodeID> &middle_nodes_table,
|
std::vector<NodeID> &middle_nodes_table,
|
||||||
const PhantomNode &phantom_node)
|
const PhantomNodeCandidates &candidates)
|
||||||
{
|
{
|
||||||
// Take a copy of the extracted node because otherwise could be modified later if toHeapNode is
|
// Take a copy of the extracted node because otherwise could be modified later if toHeapNode is
|
||||||
// the same
|
// the same
|
||||||
@ -455,7 +462,7 @@ void forwardRoutingStep(const DataFacade<Algorithm> &facade,
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
relaxOutgoingEdges<DIRECTION>(facade, heapNode, query_heap, phantom_node);
|
relaxOutgoingEdges<DIRECTION>(facade, heapNode, query_heap, candidates);
|
||||||
}
|
}
|
||||||
|
|
||||||
template <bool DIRECTION>
|
template <bool DIRECTION>
|
||||||
@ -463,7 +470,7 @@ void backwardRoutingStep(const DataFacade<Algorithm> &facade,
|
|||||||
const unsigned column_idx,
|
const unsigned column_idx,
|
||||||
typename SearchEngineData<Algorithm>::ManyToManyQueryHeap &query_heap,
|
typename SearchEngineData<Algorithm>::ManyToManyQueryHeap &query_heap,
|
||||||
std::vector<NodeBucket> &search_space_with_buckets,
|
std::vector<NodeBucket> &search_space_with_buckets,
|
||||||
const PhantomNode &phantom_node)
|
const PhantomNodeCandidates &candidates)
|
||||||
{
|
{
|
||||||
// Take a copy of the extracted node because otherwise could be modified later if toHeapNode is
|
// Take a copy of the extracted node because otherwise could be modified later if toHeapNode is
|
||||||
// the same
|
// the same
|
||||||
@ -481,7 +488,7 @@ void backwardRoutingStep(const DataFacade<Algorithm> &facade,
|
|||||||
const auto &partition = facade.GetMultiLevelPartition();
|
const auto &partition = facade.GetMultiLevelPartition();
|
||||||
const auto maximal_level = partition.GetNumberOfLevels() - 1;
|
const auto maximal_level = partition.GetNumberOfLevels() - 1;
|
||||||
|
|
||||||
relaxOutgoingEdges<!DIRECTION>(facade, heapNode, query_heap, phantom_node, maximal_level);
|
relaxOutgoingEdges<!DIRECTION>(facade, heapNode, query_heap, candidates, maximal_level);
|
||||||
}
|
}
|
||||||
|
|
||||||
template <bool DIRECTION>
|
template <bool DIRECTION>
|
||||||
@ -524,7 +531,7 @@ template <bool DIRECTION>
|
|||||||
std::pair<std::vector<EdgeDuration>, std::vector<EdgeDistance>>
|
std::pair<std::vector<EdgeDuration>, std::vector<EdgeDistance>>
|
||||||
manyToManySearch(SearchEngineData<Algorithm> &engine_working_data,
|
manyToManySearch(SearchEngineData<Algorithm> &engine_working_data,
|
||||||
const DataFacade<Algorithm> &facade,
|
const DataFacade<Algorithm> &facade,
|
||||||
const std::vector<PhantomNode> &phantom_nodes,
|
const std::vector<PhantomNodeCandidates> &candidates_list,
|
||||||
const std::vector<std::size_t> &source_indices,
|
const std::vector<std::size_t> &source_indices,
|
||||||
const std::vector<std::size_t> &target_indices,
|
const std::vector<std::size_t> &target_indices,
|
||||||
const bool calculate_distance)
|
const bool calculate_distance)
|
||||||
@ -545,22 +552,22 @@ manyToManySearch(SearchEngineData<Algorithm> &engine_working_data,
|
|||||||
for (std::uint32_t column_idx = 0; column_idx < target_indices.size(); ++column_idx)
|
for (std::uint32_t column_idx = 0; column_idx < target_indices.size(); ++column_idx)
|
||||||
{
|
{
|
||||||
const auto index = target_indices[column_idx];
|
const auto index = target_indices[column_idx];
|
||||||
const auto &target_phantom = phantom_nodes[index];
|
const auto &target_candidates = candidates_list[index];
|
||||||
|
|
||||||
engine_working_data.InitializeOrClearManyToManyThreadLocalStorage(
|
engine_working_data.InitializeOrClearManyToManyThreadLocalStorage(
|
||||||
facade.GetNumberOfNodes(), facade.GetMaxBorderNodeID() + 1);
|
facade.GetNumberOfNodes(), facade.GetMaxBorderNodeID() + 1);
|
||||||
auto &query_heap = *(engine_working_data.many_to_many_heap);
|
auto &query_heap = *(engine_working_data.many_to_many_heap);
|
||||||
|
|
||||||
if (DIRECTION == FORWARD_DIRECTION)
|
if (DIRECTION == FORWARD_DIRECTION)
|
||||||
insertTargetInHeap(query_heap, target_phantom);
|
insertTargetInHeap(query_heap, target_candidates);
|
||||||
else
|
else
|
||||||
insertSourceInHeap(query_heap, target_phantom);
|
insertSourceInHeap(query_heap, target_candidates);
|
||||||
|
|
||||||
// explore search space
|
// explore search space
|
||||||
while (!query_heap.Empty())
|
while (!query_heap.Empty())
|
||||||
{
|
{
|
||||||
backwardRoutingStep<DIRECTION>(
|
backwardRoutingStep<DIRECTION>(
|
||||||
facade, column_idx, query_heap, search_space_with_buckets, target_phantom);
|
facade, column_idx, query_heap, search_space_with_buckets, target_candidates);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -571,7 +578,7 @@ manyToManySearch(SearchEngineData<Algorithm> &engine_working_data,
|
|||||||
for (std::uint32_t row_idx = 0; row_idx < source_indices.size(); ++row_idx)
|
for (std::uint32_t row_idx = 0; row_idx < source_indices.size(); ++row_idx)
|
||||||
{
|
{
|
||||||
const auto source_index = source_indices[row_idx];
|
const auto source_index = source_indices[row_idx];
|
||||||
const auto &source_phantom = phantom_nodes[source_index];
|
const auto &source_candidates = candidates_list[source_index];
|
||||||
|
|
||||||
// Clear heap and insert source nodes
|
// Clear heap and insert source nodes
|
||||||
engine_working_data.InitializeOrClearManyToManyThreadLocalStorage(
|
engine_working_data.InitializeOrClearManyToManyThreadLocalStorage(
|
||||||
@ -580,9 +587,9 @@ manyToManySearch(SearchEngineData<Algorithm> &engine_working_data,
|
|||||||
auto &query_heap = *(engine_working_data.many_to_many_heap);
|
auto &query_heap = *(engine_working_data.many_to_many_heap);
|
||||||
|
|
||||||
if (DIRECTION == FORWARD_DIRECTION)
|
if (DIRECTION == FORWARD_DIRECTION)
|
||||||
insertSourceInHeap(query_heap, source_phantom);
|
insertSourceInHeap(query_heap, source_candidates);
|
||||||
else
|
else
|
||||||
insertTargetInHeap(query_heap, source_phantom);
|
insertTargetInHeap(query_heap, source_candidates);
|
||||||
|
|
||||||
// Explore search space
|
// Explore search space
|
||||||
while (!query_heap.Empty())
|
while (!query_heap.Empty())
|
||||||
@ -597,7 +604,7 @@ manyToManySearch(SearchEngineData<Algorithm> &engine_working_data,
|
|||||||
durations_table,
|
durations_table,
|
||||||
distances_table,
|
distances_table,
|
||||||
middle_nodes_table,
|
middle_nodes_table,
|
||||||
source_phantom);
|
source_candidates);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -622,7 +629,7 @@ template <>
|
|||||||
std::pair<std::vector<EdgeDuration>, std::vector<EdgeDistance>>
|
std::pair<std::vector<EdgeDuration>, std::vector<EdgeDistance>>
|
||||||
manyToManySearch(SearchEngineData<mld::Algorithm> &engine_working_data,
|
manyToManySearch(SearchEngineData<mld::Algorithm> &engine_working_data,
|
||||||
const DataFacade<mld::Algorithm> &facade,
|
const DataFacade<mld::Algorithm> &facade,
|
||||||
const std::vector<PhantomNode> &phantom_nodes,
|
const std::vector<PhantomNodeCandidates> &candidates_list,
|
||||||
const std::vector<std::size_t> &source_indices,
|
const std::vector<std::size_t> &source_indices,
|
||||||
const std::vector<std::size_t> &target_indices,
|
const std::vector<std::size_t> &target_indices,
|
||||||
const bool calculate_distance)
|
const bool calculate_distance)
|
||||||
@ -631,7 +638,7 @@ manyToManySearch(SearchEngineData<mld::Algorithm> &engine_working_data,
|
|||||||
{ // TODO: check if target_indices.size() == 1 and do a bi-directional search
|
{ // TODO: check if target_indices.size() == 1 and do a bi-directional search
|
||||||
return mld::oneToManySearch<FORWARD_DIRECTION>(engine_working_data,
|
return mld::oneToManySearch<FORWARD_DIRECTION>(engine_working_data,
|
||||||
facade,
|
facade,
|
||||||
phantom_nodes,
|
candidates_list,
|
||||||
source_indices.front(),
|
source_indices.front(),
|
||||||
target_indices,
|
target_indices,
|
||||||
calculate_distance);
|
calculate_distance);
|
||||||
@ -641,7 +648,7 @@ manyToManySearch(SearchEngineData<mld::Algorithm> &engine_working_data,
|
|||||||
{
|
{
|
||||||
return mld::oneToManySearch<REVERSE_DIRECTION>(engine_working_data,
|
return mld::oneToManySearch<REVERSE_DIRECTION>(engine_working_data,
|
||||||
facade,
|
facade,
|
||||||
phantom_nodes,
|
candidates_list,
|
||||||
target_indices.front(),
|
target_indices.front(),
|
||||||
source_indices,
|
source_indices,
|
||||||
calculate_distance);
|
calculate_distance);
|
||||||
@ -651,7 +658,7 @@ manyToManySearch(SearchEngineData<mld::Algorithm> &engine_working_data,
|
|||||||
{
|
{
|
||||||
return mld::manyToManySearch<REVERSE_DIRECTION>(engine_working_data,
|
return mld::manyToManySearch<REVERSE_DIRECTION>(engine_working_data,
|
||||||
facade,
|
facade,
|
||||||
phantom_nodes,
|
candidates_list,
|
||||||
target_indices,
|
target_indices,
|
||||||
source_indices,
|
source_indices,
|
||||||
calculate_distance);
|
calculate_distance);
|
||||||
@ -659,7 +666,7 @@ manyToManySearch(SearchEngineData<mld::Algorithm> &engine_working_data,
|
|||||||
|
|
||||||
return mld::manyToManySearch<FORWARD_DIRECTION>(engine_working_data,
|
return mld::manyToManySearch<FORWARD_DIRECTION>(engine_working_data,
|
||||||
facade,
|
facade,
|
||||||
phantom_nodes,
|
candidates_list,
|
||||||
source_indices,
|
source_indices,
|
||||||
target_indices,
|
target_indices,
|
||||||
calculate_distance);
|
calculate_distance);
|
||||||
|
|||||||
@ -7,30 +7,104 @@ namespace engine
|
|||||||
namespace routing_algorithms
|
namespace routing_algorithms
|
||||||
{
|
{
|
||||||
|
|
||||||
bool needsLoopForward(const PhantomNode &source_phantom, const PhantomNode &target_phantom)
|
bool requiresForwardLoop(const PhantomNode &source, const PhantomNode &target)
|
||||||
{
|
{
|
||||||
return source_phantom.IsValidForwardSource() && target_phantom.IsValidForwardTarget() &&
|
return source.IsValidForwardSource() && target.IsValidForwardTarget() &&
|
||||||
source_phantom.forward_segment_id.id == target_phantom.forward_segment_id.id &&
|
source.forward_segment_id.id == target.forward_segment_id.id &&
|
||||||
source_phantom.GetForwardWeightPlusOffset() >
|
source.GetForwardWeightPlusOffset() > target.GetForwardWeightPlusOffset();
|
||||||
target_phantom.GetForwardWeightPlusOffset();
|
|
||||||
}
|
}
|
||||||
|
|
||||||
bool needsLoopBackwards(const PhantomNode &source_phantom, const PhantomNode &target_phantom)
|
bool requiresBackwardLoop(const PhantomNode &source, const PhantomNode &target)
|
||||||
{
|
{
|
||||||
return source_phantom.IsValidReverseSource() && target_phantom.IsValidReverseTarget() &&
|
return source.IsValidReverseSource() && target.IsValidReverseTarget() &&
|
||||||
source_phantom.reverse_segment_id.id == target_phantom.reverse_segment_id.id &&
|
source.reverse_segment_id.id == target.reverse_segment_id.id &&
|
||||||
source_phantom.GetReverseWeightPlusOffset() >
|
source.GetReverseWeightPlusOffset() > target.GetReverseWeightPlusOffset();
|
||||||
target_phantom.GetReverseWeightPlusOffset();
|
|
||||||
}
|
}
|
||||||
|
|
||||||
bool needsLoopForward(const PhantomNodes &phantoms)
|
std::vector<NodeID> getForwardLoopNodes(const PhantomEndpointCandidates &endpoint_candidates)
|
||||||
{
|
{
|
||||||
return needsLoopForward(phantoms.source_phantom, phantoms.target_phantom);
|
std::vector<NodeID> res;
|
||||||
|
for (const auto &source_phantom : endpoint_candidates.source_phantoms)
|
||||||
|
{
|
||||||
|
auto requires_loop =
|
||||||
|
std::any_of(endpoint_candidates.target_phantoms.begin(),
|
||||||
|
endpoint_candidates.target_phantoms.end(),
|
||||||
|
[&](const auto &target_phantom) {
|
||||||
|
return requiresForwardLoop(source_phantom, target_phantom);
|
||||||
|
});
|
||||||
|
if (requires_loop)
|
||||||
|
{
|
||||||
|
res.push_back(source_phantom.forward_segment_id.id);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return res;
|
||||||
}
|
}
|
||||||
|
|
||||||
bool needsLoopBackwards(const PhantomNodes &phantoms)
|
std::vector<NodeID> getForwardLoopNodes(const PhantomCandidatesToTarget &endpoint_candidates)
|
||||||
{
|
{
|
||||||
return needsLoopBackwards(phantoms.source_phantom, phantoms.target_phantom);
|
std::vector<NodeID> res;
|
||||||
|
for (const auto &source_phantom : endpoint_candidates.source_phantoms)
|
||||||
|
{
|
||||||
|
if (requiresForwardLoop(source_phantom, endpoint_candidates.target_phantom))
|
||||||
|
{
|
||||||
|
res.push_back(source_phantom.forward_segment_id.id);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return res;
|
||||||
|
}
|
||||||
|
|
||||||
|
std::vector<NodeID> getBackwardLoopNodes(const PhantomEndpointCandidates &endpoint_candidates)
|
||||||
|
{
|
||||||
|
std::vector<NodeID> res;
|
||||||
|
for (const auto &source_phantom : endpoint_candidates.source_phantoms)
|
||||||
|
{
|
||||||
|
auto requires_loop =
|
||||||
|
std::any_of(endpoint_candidates.target_phantoms.begin(),
|
||||||
|
endpoint_candidates.target_phantoms.end(),
|
||||||
|
[&](const auto &target_phantom) {
|
||||||
|
return requiresBackwardLoop(source_phantom, target_phantom);
|
||||||
|
});
|
||||||
|
if (requires_loop)
|
||||||
|
{
|
||||||
|
res.push_back(source_phantom.reverse_segment_id.id);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return res;
|
||||||
|
}
|
||||||
|
|
||||||
|
std::vector<NodeID> getBackwardLoopNodes(const PhantomCandidatesToTarget &endpoint_candidates)
|
||||||
|
{
|
||||||
|
std::vector<NodeID> res;
|
||||||
|
for (const auto &source_phantom : endpoint_candidates.source_phantoms)
|
||||||
|
{
|
||||||
|
if (requiresBackwardLoop(source_phantom, endpoint_candidates.target_phantom))
|
||||||
|
{
|
||||||
|
res.push_back(source_phantom.reverse_segment_id.id);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return res;
|
||||||
|
}
|
||||||
|
|
||||||
|
PhantomEndpoints endpointsFromCandidates(const PhantomEndpointCandidates &candidates,
|
||||||
|
const std::vector<NodeID> &path)
|
||||||
|
{
|
||||||
|
auto source_it = std::find_if(candidates.source_phantoms.begin(),
|
||||||
|
candidates.source_phantoms.end(),
|
||||||
|
[&path](const auto &source_phantom) {
|
||||||
|
return path.front() == source_phantom.forward_segment_id.id ||
|
||||||
|
path.front() == source_phantom.reverse_segment_id.id;
|
||||||
|
});
|
||||||
|
BOOST_ASSERT(source_it != candidates.source_phantoms.end());
|
||||||
|
|
||||||
|
auto target_it = std::find_if(candidates.target_phantoms.begin(),
|
||||||
|
candidates.target_phantoms.end(),
|
||||||
|
[&path](const auto &target_phantom) {
|
||||||
|
return path.back() == target_phantom.forward_segment_id.id ||
|
||||||
|
path.back() == target_phantom.reverse_segment_id.id;
|
||||||
|
});
|
||||||
|
BOOST_ASSERT(target_it != candidates.target_phantoms.end());
|
||||||
|
|
||||||
|
return PhantomEndpoints{*source_it, *target_it};
|
||||||
}
|
}
|
||||||
|
|
||||||
} // namespace routing_algorithms
|
} // namespace routing_algorithms
|
||||||
|
|||||||
@ -95,9 +95,8 @@ void search(SearchEngineData<Algorithm> & /*engine_working_data*/,
|
|||||||
SearchEngineData<Algorithm>::QueryHeap &reverse_heap,
|
SearchEngineData<Algorithm>::QueryHeap &reverse_heap,
|
||||||
EdgeWeight &weight,
|
EdgeWeight &weight,
|
||||||
std::vector<NodeID> &packed_leg,
|
std::vector<NodeID> &packed_leg,
|
||||||
const bool force_loop_forward,
|
const std::vector<NodeID> &force_loop_forward_nodes,
|
||||||
const bool force_loop_reverse,
|
const std::vector<NodeID> &force_loop_reverse_nodes,
|
||||||
const PhantomNodes & /*phantom_nodes*/,
|
|
||||||
const EdgeWeight weight_upper_bound)
|
const EdgeWeight weight_upper_bound)
|
||||||
{
|
{
|
||||||
if (forward_heap.Empty() || reverse_heap.Empty())
|
if (forward_heap.Empty() || reverse_heap.Empty())
|
||||||
@ -126,8 +125,8 @@ void search(SearchEngineData<Algorithm> & /*engine_working_data*/,
|
|||||||
middle,
|
middle,
|
||||||
weight,
|
weight,
|
||||||
min_edge_offset,
|
min_edge_offset,
|
||||||
force_loop_forward,
|
force_loop_forward_nodes,
|
||||||
force_loop_reverse);
|
force_loop_reverse_nodes);
|
||||||
}
|
}
|
||||||
if (!reverse_heap.Empty())
|
if (!reverse_heap.Empty())
|
||||||
{
|
{
|
||||||
@ -137,8 +136,8 @@ void search(SearchEngineData<Algorithm> & /*engine_working_data*/,
|
|||||||
middle,
|
middle,
|
||||||
weight,
|
weight,
|
||||||
min_edge_offset,
|
min_edge_offset,
|
||||||
force_loop_reverse,
|
force_loop_reverse_nodes,
|
||||||
force_loop_forward);
|
force_loop_forward_nodes);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -179,7 +178,8 @@ double getNetworkDistance(SearchEngineData<Algorithm> &engine_working_data,
|
|||||||
forward_heap.Clear();
|
forward_heap.Clear();
|
||||||
reverse_heap.Clear();
|
reverse_heap.Clear();
|
||||||
|
|
||||||
insertNodesInHeaps(forward_heap, reverse_heap, {source_phantom, target_phantom});
|
PhantomEndpoints endpoints{source_phantom, target_phantom};
|
||||||
|
insertNodesInHeaps(forward_heap, reverse_heap, endpoints);
|
||||||
|
|
||||||
EdgeWeight weight = INVALID_EDGE_WEIGHT;
|
EdgeWeight weight = INVALID_EDGE_WEIGHT;
|
||||||
std::vector<NodeID> packed_path;
|
std::vector<NodeID> packed_path;
|
||||||
@ -189,9 +189,9 @@ double getNetworkDistance(SearchEngineData<Algorithm> &engine_working_data,
|
|||||||
reverse_heap,
|
reverse_heap,
|
||||||
weight,
|
weight,
|
||||||
packed_path,
|
packed_path,
|
||||||
DO_NOT_FORCE_LOOPS,
|
{},
|
||||||
DO_NOT_FORCE_LOOPS,
|
{},
|
||||||
{source_phantom, target_phantom},
|
endpoints,
|
||||||
weight_upper_bound);
|
weight_upper_bound);
|
||||||
|
|
||||||
if (weight == INVALID_EDGE_WEIGHT)
|
if (weight == INVALID_EDGE_WEIGHT)
|
||||||
|
|||||||
@ -12,13 +12,13 @@ namespace routing_algorithms
|
|||||||
template InternalRouteResult
|
template InternalRouteResult
|
||||||
shortestPathSearch(SearchEngineData<ch::Algorithm> &engine_working_data,
|
shortestPathSearch(SearchEngineData<ch::Algorithm> &engine_working_data,
|
||||||
const DataFacade<ch::Algorithm> &facade,
|
const DataFacade<ch::Algorithm> &facade,
|
||||||
const std::vector<PhantomNodes> &phantom_nodes_vector,
|
const std::vector<PhantomNodeCandidates> &waypoint_candidates,
|
||||||
const boost::optional<bool> continue_straight_at_waypoint);
|
const boost::optional<bool> continue_straight_at_waypoint);
|
||||||
|
|
||||||
template InternalRouteResult
|
template InternalRouteResult
|
||||||
shortestPathSearch(SearchEngineData<mld::Algorithm> &engine_working_data,
|
shortestPathSearch(SearchEngineData<mld::Algorithm> &engine_working_data,
|
||||||
const DataFacade<mld::Algorithm> &facade,
|
const DataFacade<mld::Algorithm> &facade,
|
||||||
const std::vector<PhantomNodes> &phantom_nodes_vector,
|
const std::vector<PhantomNodeCandidates> &waypoint_candidates,
|
||||||
const boost::optional<bool> continue_straight_at_waypoint);
|
const boost::optional<bool> continue_straight_at_waypoint);
|
||||||
|
|
||||||
} // namespace routing_algorithms
|
} // namespace routing_algorithms
|
||||||
|
|||||||
@ -44,16 +44,16 @@ BOOST_AUTO_TEST_CASE(hint_encoding_decoding_roundtrip)
|
|||||||
const PhantomNode phantom;
|
const PhantomNode phantom;
|
||||||
const osrm::test::MockDataFacade<osrm::engine::routing_algorithms::ch::Algorithm> facade{};
|
const osrm::test::MockDataFacade<osrm::engine::routing_algorithms::ch::Algorithm> facade{};
|
||||||
|
|
||||||
const Hint hint{phantom, facade.GetCheckSum()};
|
const SegmentHint seg_hint{phantom, facade.GetCheckSum()};
|
||||||
|
|
||||||
const auto base64 = hint.ToBase64();
|
const auto base64 = seg_hint.ToBase64();
|
||||||
|
|
||||||
BOOST_CHECK(0 == std::count(begin(base64), end(base64), '+'));
|
BOOST_CHECK(0 == std::count(begin(base64), end(base64), '+'));
|
||||||
BOOST_CHECK(0 == std::count(begin(base64), end(base64), '/'));
|
BOOST_CHECK(0 == std::count(begin(base64), end(base64), '/'));
|
||||||
|
|
||||||
const auto decoded = Hint::FromBase64(base64);
|
const auto decoded = SegmentHint::FromBase64(base64);
|
||||||
|
|
||||||
BOOST_CHECK_EQUAL(hint, decoded);
|
BOOST_CHECK_EQUAL(seg_hint, decoded);
|
||||||
}
|
}
|
||||||
|
|
||||||
BOOST_AUTO_TEST_CASE(hint_encoding_decoding_roundtrip_bytewise)
|
BOOST_AUTO_TEST_CASE(hint_encoding_decoding_roundtrip_bytewise)
|
||||||
@ -65,12 +65,12 @@ BOOST_AUTO_TEST_CASE(hint_encoding_decoding_roundtrip_bytewise)
|
|||||||
const PhantomNode phantom;
|
const PhantomNode phantom;
|
||||||
const osrm::test::MockDataFacade<osrm::engine::routing_algorithms::ch::Algorithm> facade{};
|
const osrm::test::MockDataFacade<osrm::engine::routing_algorithms::ch::Algorithm> facade{};
|
||||||
|
|
||||||
const Hint hint{phantom, facade.GetCheckSum()};
|
const SegmentHint seg_hint{phantom, facade.GetCheckSum()};
|
||||||
|
|
||||||
const auto decoded = Hint::FromBase64(hint.ToBase64());
|
const auto decoded = SegmentHint::FromBase64(seg_hint.ToBase64());
|
||||||
|
|
||||||
BOOST_CHECK(std::equal(reinterpret_cast<const unsigned char *>(&hint),
|
BOOST_CHECK(std::equal(reinterpret_cast<const unsigned char *>(&seg_hint),
|
||||||
reinterpret_cast<const unsigned char *>(&hint) + sizeof(Hint),
|
reinterpret_cast<const unsigned char *>(&seg_hint) + sizeof(Hint),
|
||||||
reinterpret_cast<const unsigned char *>(&decoded)));
|
reinterpret_cast<const unsigned char *>(&decoded)));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@ -23,7 +23,7 @@ BOOST_AUTO_TEST_CASE(unchanged_collapse_route_result)
|
|||||||
PathData kathy{0, 1, 1, 2, 3, 4, 1, boost::none};
|
PathData kathy{0, 1, 1, 2, 3, 4, 1, boost::none};
|
||||||
InternalRouteResult one_leg_result;
|
InternalRouteResult one_leg_result;
|
||||||
one_leg_result.unpacked_path_segments = {{pathy, kathy}};
|
one_leg_result.unpacked_path_segments = {{pathy, kathy}};
|
||||||
one_leg_result.segment_end_coordinates = {PhantomNodes{source, target}};
|
one_leg_result.leg_endpoints = {PhantomEndpoints{source, target}};
|
||||||
one_leg_result.source_traversed_in_reverse = {true};
|
one_leg_result.source_traversed_in_reverse = {true};
|
||||||
one_leg_result.target_traversed_in_reverse = {true};
|
one_leg_result.target_traversed_in_reverse = {true};
|
||||||
one_leg_result.shortest_path_weight = 50;
|
one_leg_result.shortest_path_weight = 50;
|
||||||
@ -50,18 +50,17 @@ BOOST_AUTO_TEST_CASE(two_legs_to_one_leg)
|
|||||||
node_3.forward_segment_id = {12, true};
|
node_3.forward_segment_id = {12, true};
|
||||||
InternalRouteResult two_leg_result;
|
InternalRouteResult two_leg_result;
|
||||||
two_leg_result.unpacked_path_segments = {{pathy, kathy}, {kathy, cathy}};
|
two_leg_result.unpacked_path_segments = {{pathy, kathy}, {kathy, cathy}};
|
||||||
two_leg_result.segment_end_coordinates = {PhantomNodes{node_1, node_2},
|
two_leg_result.leg_endpoints = {PhantomEndpoints{node_1, node_2},
|
||||||
PhantomNodes{node_2, node_3}};
|
PhantomEndpoints{node_2, node_3}};
|
||||||
two_leg_result.source_traversed_in_reverse = {true, false};
|
two_leg_result.source_traversed_in_reverse = {true, false};
|
||||||
two_leg_result.target_traversed_in_reverse = {true, false};
|
two_leg_result.target_traversed_in_reverse = {true, false};
|
||||||
two_leg_result.shortest_path_weight = 80;
|
two_leg_result.shortest_path_weight = 80;
|
||||||
|
|
||||||
auto collapsed = CollapseInternalRouteResult(two_leg_result, {true, false, true, true});
|
auto collapsed = CollapseInternalRouteResult(two_leg_result, {true, false, true, true});
|
||||||
BOOST_CHECK_EQUAL(collapsed.unpacked_path_segments.size(), 1);
|
BOOST_CHECK_EQUAL(collapsed.unpacked_path_segments.size(), 1);
|
||||||
BOOST_CHECK_EQUAL(collapsed.segment_end_coordinates.size(), 1);
|
BOOST_CHECK_EQUAL(collapsed.leg_endpoints.size(), 1);
|
||||||
BOOST_CHECK_EQUAL(collapsed.segment_end_coordinates[0].target_phantom.forward_segment_id.id,
|
BOOST_CHECK_EQUAL(collapsed.leg_endpoints[0].target_phantom.forward_segment_id.id, 12);
|
||||||
12);
|
BOOST_CHECK_EQUAL(collapsed.leg_endpoints[0].source_phantom.forward_segment_id.id, 1);
|
||||||
BOOST_CHECK_EQUAL(collapsed.segment_end_coordinates[0].source_phantom.forward_segment_id.id, 1);
|
|
||||||
BOOST_CHECK_EQUAL(collapsed.unpacked_path_segments[0].size(), 4);
|
BOOST_CHECK_EQUAL(collapsed.unpacked_path_segments[0].size(), 4);
|
||||||
BOOST_CHECK_EQUAL(collapsed.unpacked_path_segments[0][0].turn_via_node, 2);
|
BOOST_CHECK_EQUAL(collapsed.unpacked_path_segments[0][0].turn_via_node, 2);
|
||||||
BOOST_CHECK_EQUAL(collapsed.unpacked_path_segments[0][1].turn_via_node, 1);
|
BOOST_CHECK_EQUAL(collapsed.unpacked_path_segments[0][1].turn_via_node, 1);
|
||||||
@ -88,20 +87,20 @@ BOOST_AUTO_TEST_CASE(three_legs_to_two_legs)
|
|||||||
three_leg_result.unpacked_path_segments = {std::vector<PathData>{pathy, kathy},
|
three_leg_result.unpacked_path_segments = {std::vector<PathData>{pathy, kathy},
|
||||||
std::vector<PathData>{kathy, qathy, cathy},
|
std::vector<PathData>{kathy, qathy, cathy},
|
||||||
std::vector<PathData>{cathy, mathy}};
|
std::vector<PathData>{cathy, mathy}};
|
||||||
three_leg_result.segment_end_coordinates = {
|
three_leg_result.leg_endpoints = {PhantomEndpoints{node_1, node_2},
|
||||||
PhantomNodes{node_1, node_2}, PhantomNodes{node_2, node_3}, PhantomNodes{node_3, node_4}};
|
PhantomEndpoints{node_2, node_3},
|
||||||
|
PhantomEndpoints{node_3, node_4}};
|
||||||
three_leg_result.source_traversed_in_reverse = {true, false, true},
|
three_leg_result.source_traversed_in_reverse = {true, false, true},
|
||||||
three_leg_result.target_traversed_in_reverse = {true, false, true},
|
three_leg_result.target_traversed_in_reverse = {true, false, true},
|
||||||
three_leg_result.shortest_path_weight = 140;
|
three_leg_result.shortest_path_weight = 140;
|
||||||
|
|
||||||
auto collapsed = CollapseInternalRouteResult(three_leg_result, {true, true, false, true});
|
auto collapsed = CollapseInternalRouteResult(three_leg_result, {true, true, false, true});
|
||||||
BOOST_CHECK_EQUAL(collapsed.unpacked_path_segments.size(), 2);
|
BOOST_CHECK_EQUAL(collapsed.unpacked_path_segments.size(), 2);
|
||||||
BOOST_CHECK_EQUAL(collapsed.segment_end_coordinates.size(), 2);
|
BOOST_CHECK_EQUAL(collapsed.leg_endpoints.size(), 2);
|
||||||
BOOST_CHECK_EQUAL(collapsed.segment_end_coordinates[0].source_phantom.forward_segment_id.id, 1);
|
BOOST_CHECK_EQUAL(collapsed.leg_endpoints[0].source_phantom.forward_segment_id.id, 1);
|
||||||
BOOST_CHECK_EQUAL(collapsed.segment_end_coordinates[0].target_phantom.forward_segment_id.id, 6);
|
BOOST_CHECK_EQUAL(collapsed.leg_endpoints[0].target_phantom.forward_segment_id.id, 6);
|
||||||
BOOST_CHECK_EQUAL(collapsed.segment_end_coordinates[1].source_phantom.forward_segment_id.id, 6);
|
BOOST_CHECK_EQUAL(collapsed.leg_endpoints[1].source_phantom.forward_segment_id.id, 6);
|
||||||
BOOST_CHECK_EQUAL(collapsed.segment_end_coordinates[1].target_phantom.forward_segment_id.id,
|
BOOST_CHECK_EQUAL(collapsed.leg_endpoints[1].target_phantom.forward_segment_id.id, 18);
|
||||||
18);
|
|
||||||
BOOST_CHECK_EQUAL(collapsed.unpacked_path_segments[0].size(), 2);
|
BOOST_CHECK_EQUAL(collapsed.unpacked_path_segments[0].size(), 2);
|
||||||
BOOST_CHECK_EQUAL(collapsed.unpacked_path_segments[1].size(), 5);
|
BOOST_CHECK_EQUAL(collapsed.unpacked_path_segments[1].size(), 5);
|
||||||
BOOST_CHECK_EQUAL(collapsed.unpacked_path_segments[0][0].turn_via_node, 2);
|
BOOST_CHECK_EQUAL(collapsed.unpacked_path_segments[0][0].turn_via_node, 2);
|
||||||
@ -126,20 +125,19 @@ BOOST_AUTO_TEST_CASE(two_legs_to_two_legs)
|
|||||||
node_3.forward_segment_id = {12, true};
|
node_3.forward_segment_id = {12, true};
|
||||||
InternalRouteResult two_leg_result;
|
InternalRouteResult two_leg_result;
|
||||||
two_leg_result.unpacked_path_segments = {{pathy, kathy}, {kathy, cathy}};
|
two_leg_result.unpacked_path_segments = {{pathy, kathy}, {kathy, cathy}};
|
||||||
two_leg_result.segment_end_coordinates = {PhantomNodes{node_1, node_2},
|
two_leg_result.leg_endpoints = {PhantomEndpoints{node_1, node_2},
|
||||||
PhantomNodes{node_2, node_3}};
|
PhantomEndpoints{node_2, node_3}};
|
||||||
two_leg_result.source_traversed_in_reverse = {true, false};
|
two_leg_result.source_traversed_in_reverse = {true, false};
|
||||||
two_leg_result.target_traversed_in_reverse = {true, false};
|
two_leg_result.target_traversed_in_reverse = {true, false};
|
||||||
two_leg_result.shortest_path_weight = 80;
|
two_leg_result.shortest_path_weight = 80;
|
||||||
|
|
||||||
auto collapsed = CollapseInternalRouteResult(two_leg_result, {true, true, true});
|
auto collapsed = CollapseInternalRouteResult(two_leg_result, {true, true, true});
|
||||||
BOOST_CHECK_EQUAL(collapsed.unpacked_path_segments.size(), 2);
|
BOOST_CHECK_EQUAL(collapsed.unpacked_path_segments.size(), 2);
|
||||||
BOOST_CHECK_EQUAL(collapsed.segment_end_coordinates.size(), 2);
|
BOOST_CHECK_EQUAL(collapsed.leg_endpoints.size(), 2);
|
||||||
BOOST_CHECK_EQUAL(collapsed.segment_end_coordinates[0].source_phantom.forward_segment_id.id, 1);
|
BOOST_CHECK_EQUAL(collapsed.leg_endpoints[0].source_phantom.forward_segment_id.id, 1);
|
||||||
BOOST_CHECK_EQUAL(collapsed.segment_end_coordinates[0].target_phantom.forward_segment_id.id, 6);
|
BOOST_CHECK_EQUAL(collapsed.leg_endpoints[0].target_phantom.forward_segment_id.id, 6);
|
||||||
BOOST_CHECK_EQUAL(collapsed.segment_end_coordinates[1].source_phantom.forward_segment_id.id, 6);
|
BOOST_CHECK_EQUAL(collapsed.leg_endpoints[1].source_phantom.forward_segment_id.id, 6);
|
||||||
BOOST_CHECK_EQUAL(collapsed.segment_end_coordinates[1].target_phantom.forward_segment_id.id,
|
BOOST_CHECK_EQUAL(collapsed.leg_endpoints[1].target_phantom.forward_segment_id.id, 12);
|
||||||
12);
|
|
||||||
BOOST_CHECK_EQUAL(collapsed.unpacked_path_segments[0].size(), 2);
|
BOOST_CHECK_EQUAL(collapsed.unpacked_path_segments[0].size(), 2);
|
||||||
BOOST_CHECK_EQUAL(collapsed.unpacked_path_segments[1].size(), 2);
|
BOOST_CHECK_EQUAL(collapsed.unpacked_path_segments[1].size(), 2);
|
||||||
BOOST_CHECK_EQUAL(collapsed.unpacked_path_segments[0][0].turn_via_node, 2);
|
BOOST_CHECK_EQUAL(collapsed.unpacked_path_segments[0][0].turn_via_node, 2);
|
||||||
|
|||||||
@ -224,101 +224,35 @@ class ContiguousInternalMemoryDataFacade<routing_algorithms::offline::Algorithm>
|
|||||||
return {};
|
return {};
|
||||||
}
|
}
|
||||||
|
|
||||||
std::vector<PhantomNodeWithDistance>
|
std::vector<engine::PhantomNodeWithDistance>
|
||||||
NearestPhantomNodesInRange(const util::Coordinate /*input_coordinate*/,
|
NearestPhantomNodesInRange(const util::Coordinate /*input_coordinate*/,
|
||||||
const float /*max_distance*/,
|
const double /*max_distance*/,
|
||||||
const int /*bearing*/,
|
const boost::optional<engine::Bearing> /*bearing*/,
|
||||||
const int /*bearing_range*/,
|
const engine::Approach /*approach*/,
|
||||||
const Approach /*approach*/,
|
|
||||||
const bool /*use_all_edges*/) const override
|
const bool /*use_all_edges*/) const override
|
||||||
{
|
{
|
||||||
return {};
|
return {};
|
||||||
}
|
};
|
||||||
|
|
||||||
std::vector<PhantomNodeWithDistance>
|
std::vector<engine::PhantomNodeWithDistance>
|
||||||
NearestPhantomNodesInRange(const util::Coordinate /*input_coordinate*/,
|
|
||||||
const float /*max_distance*/,
|
|
||||||
const Approach /*approach*/,
|
|
||||||
const bool /*use_all_edges*/) const override
|
|
||||||
{
|
|
||||||
return {};
|
|
||||||
}
|
|
||||||
|
|
||||||
std::vector<PhantomNodeWithDistance>
|
|
||||||
NearestPhantomNodes(const util::Coordinate /*input_coordinate*/,
|
NearestPhantomNodes(const util::Coordinate /*input_coordinate*/,
|
||||||
const unsigned /*max_results*/,
|
const size_t /*max_results*/,
|
||||||
const double /*max_distance*/,
|
const boost::optional<double> /*max_distance*/,
|
||||||
const int /*bearing*/,
|
const boost::optional<engine::Bearing> /*bearing*/,
|
||||||
const int /*bearing_range*/,
|
const engine::Approach /*approach*/) const override
|
||||||
const Approach /*approach*/) const override
|
|
||||||
{
|
{
|
||||||
return {};
|
return {};
|
||||||
}
|
};
|
||||||
|
|
||||||
std::vector<PhantomNodeWithDistance>
|
engine::PhantomCandidateAlternatives NearestCandidatesWithAlternativeFromBigComponent(
|
||||||
NearestPhantomNodes(const util::Coordinate /*input_coordinate*/,
|
const util::Coordinate /*input_coordinate*/,
|
||||||
const unsigned /*max_results*/,
|
const boost::optional<double> /*max_distance*/,
|
||||||
const int /*bearing*/,
|
const boost::optional<engine::Bearing> /*bearing*/,
|
||||||
const int /*bearing_range*/,
|
const engine::Approach /*approach*/,
|
||||||
const Approach /*approach*/) const override
|
const bool /*use_all_edges*/) const override
|
||||||
{
|
{
|
||||||
return {};
|
return {};
|
||||||
}
|
};
|
||||||
|
|
||||||
std::vector<PhantomNodeWithDistance>
|
|
||||||
NearestPhantomNodes(const util::Coordinate /*input_coordinate*/,
|
|
||||||
const unsigned /*max_results*/,
|
|
||||||
const Approach /*approach*/) const override
|
|
||||||
{
|
|
||||||
return {};
|
|
||||||
}
|
|
||||||
|
|
||||||
std::vector<PhantomNodeWithDistance>
|
|
||||||
NearestPhantomNodes(const util::Coordinate /*input_coordinate*/,
|
|
||||||
const unsigned /*max_results*/,
|
|
||||||
const double /*max_distance*/,
|
|
||||||
const Approach /*approach*/) const override
|
|
||||||
{
|
|
||||||
return {};
|
|
||||||
}
|
|
||||||
|
|
||||||
std::pair<PhantomNode, PhantomNode>
|
|
||||||
NearestPhantomNodeWithAlternativeFromBigComponent(const util::Coordinate /*input_coordinate*/,
|
|
||||||
const Approach /*approach*/,
|
|
||||||
const bool /* use_all_edges */) const override
|
|
||||||
{
|
|
||||||
return {};
|
|
||||||
}
|
|
||||||
|
|
||||||
std::pair<PhantomNode, PhantomNode>
|
|
||||||
NearestPhantomNodeWithAlternativeFromBigComponent(const util::Coordinate /*input_coordinate*/,
|
|
||||||
const double /*max_distance*/,
|
|
||||||
const Approach /*approach*/,
|
|
||||||
const bool /* use_all_edges */) const override
|
|
||||||
{
|
|
||||||
return {};
|
|
||||||
}
|
|
||||||
|
|
||||||
std::pair<PhantomNode, PhantomNode>
|
|
||||||
NearestPhantomNodeWithAlternativeFromBigComponent(const util::Coordinate /*input_coordinate*/,
|
|
||||||
const double /*max_distance*/,
|
|
||||||
const int /*bearing*/,
|
|
||||||
const int /*bearing_range*/,
|
|
||||||
const Approach /*approach*/,
|
|
||||||
const bool /* use_all_edges */) const override
|
|
||||||
{
|
|
||||||
return {};
|
|
||||||
}
|
|
||||||
|
|
||||||
std::pair<PhantomNode, PhantomNode>
|
|
||||||
NearestPhantomNodeWithAlternativeFromBigComponent(const util::Coordinate /*input_coordinate*/,
|
|
||||||
const int /*bearing*/,
|
|
||||||
const int /*bearing_range*/,
|
|
||||||
const Approach /*approach*/,
|
|
||||||
const bool /* use_all_edges */) const override
|
|
||||||
{
|
|
||||||
return {};
|
|
||||||
}
|
|
||||||
|
|
||||||
util::guidance::LaneTupleIdPair GetLaneData(const EdgeID /*id*/) const override
|
util::guidance::LaneTupleIdPair GetLaneData(const EdgeID /*id*/) const override
|
||||||
{
|
{
|
||||||
@ -394,15 +328,16 @@ namespace routing_algorithms
|
|||||||
namespace offline
|
namespace offline
|
||||||
{
|
{
|
||||||
|
|
||||||
|
template <typename PhantomT>
|
||||||
inline void search(SearchEngineData<Algorithm> &engine_working_data,
|
inline void search(SearchEngineData<Algorithm> &engine_working_data,
|
||||||
const datafacade::ContiguousInternalMemoryDataFacade<Algorithm> &facade,
|
const datafacade::ContiguousInternalMemoryDataFacade<Algorithm> &facade,
|
||||||
typename SearchEngineData<Algorithm>::QueryHeap &forward_heap,
|
typename SearchEngineData<Algorithm>::QueryHeap &forward_heap,
|
||||||
typename SearchEngineData<Algorithm>::QueryHeap &reverse_heap,
|
typename SearchEngineData<Algorithm>::QueryHeap &reverse_heap,
|
||||||
EdgeWeight &weight,
|
EdgeWeight &weight,
|
||||||
std::vector<NodeID> &packed_leg,
|
std::vector<NodeID> &packed_leg,
|
||||||
const bool force_loop_forward,
|
const std::vector<NodeID> &forward_loop_nodes,
|
||||||
const bool force_loop_reverse,
|
const std::vector<NodeID> &reverse_loop_nodes,
|
||||||
const PhantomNodes &phantom_nodes,
|
const PhantomT &endpoints,
|
||||||
const EdgeWeight weight_upper_bound = INVALID_EDGE_WEIGHT)
|
const EdgeWeight weight_upper_bound = INVALID_EDGE_WEIGHT)
|
||||||
{
|
{
|
||||||
mld::search(engine_working_data,
|
mld::search(engine_working_data,
|
||||||
@ -411,9 +346,9 @@ inline void search(SearchEngineData<Algorithm> &engine_working_data,
|
|||||||
reverse_heap,
|
reverse_heap,
|
||||||
weight,
|
weight,
|
||||||
packed_leg,
|
packed_leg,
|
||||||
force_loop_forward,
|
forward_loop_nodes,
|
||||||
force_loop_reverse,
|
reverse_loop_nodes,
|
||||||
phantom_nodes,
|
endpoints,
|
||||||
weight_upper_bound);
|
weight_upper_bound);
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -421,10 +356,10 @@ template <typename RandomIter, typename FacadeT>
|
|||||||
void unpackPath(const FacadeT &facade,
|
void unpackPath(const FacadeT &facade,
|
||||||
RandomIter packed_path_begin,
|
RandomIter packed_path_begin,
|
||||||
RandomIter packed_path_end,
|
RandomIter packed_path_end,
|
||||||
const PhantomNodes &phantom_nodes,
|
const PhantomEndpoints &endpoints,
|
||||||
std::vector<PathData> &unpacked_path)
|
std::vector<PathData> &unpacked_path)
|
||||||
{
|
{
|
||||||
mld::unpackPath(facade, packed_path_begin, packed_path_end, phantom_nodes, unpacked_path);
|
mld::unpackPath(facade, packed_path_begin, packed_path_end, endpoints, unpacked_path);
|
||||||
}
|
}
|
||||||
|
|
||||||
} // namespace offline
|
} // namespace offline
|
||||||
@ -442,11 +377,12 @@ BOOST_AUTO_TEST_CASE(shortest_path)
|
|||||||
osrm::engine::SearchEngineData<Algorithm> heaps;
|
osrm::engine::SearchEngineData<Algorithm> heaps;
|
||||||
osrm::engine::datafacade::ContiguousInternalMemoryDataFacade<Algorithm> facade;
|
osrm::engine::datafacade::ContiguousInternalMemoryDataFacade<Algorithm> facade;
|
||||||
|
|
||||||
std::vector<osrm::engine::PhantomNodes> phantom_nodes;
|
std::vector<osrm::engine::PhantomNodeCandidates> waypoints;
|
||||||
phantom_nodes.push_back({osrm::engine::PhantomNode{}, osrm::engine::PhantomNode{}});
|
waypoints.push_back({osrm::engine::PhantomNode{}});
|
||||||
|
waypoints.push_back({osrm::engine::PhantomNode{}});
|
||||||
|
|
||||||
auto route =
|
auto route =
|
||||||
osrm::engine::routing_algorithms::shortestPathSearch(heaps, facade, phantom_nodes, false);
|
osrm::engine::routing_algorithms::shortestPathSearch(heaps, facade, waypoints, false);
|
||||||
|
|
||||||
BOOST_CHECK_EQUAL(route.shortest_path_weight, INVALID_EDGE_WEIGHT);
|
BOOST_CHECK_EQUAL(route.shortest_path_weight, INVALID_EDGE_WEIGHT);
|
||||||
}
|
}
|
||||||
|
|||||||
@ -110,99 +110,33 @@ class MockBaseDataFacade : public engine::datafacade::BaseDataFacade
|
|||||||
|
|
||||||
std::vector<engine::PhantomNodeWithDistance>
|
std::vector<engine::PhantomNodeWithDistance>
|
||||||
NearestPhantomNodesInRange(const util::Coordinate /*input_coordinate*/,
|
NearestPhantomNodesInRange(const util::Coordinate /*input_coordinate*/,
|
||||||
const float /*max_distance*/,
|
const double /*max_distance*/,
|
||||||
const int /*bearing*/,
|
const boost::optional<engine::Bearing> /*bearing*/,
|
||||||
const int /*bearing_range*/,
|
|
||||||
const engine::Approach /*approach*/,
|
const engine::Approach /*approach*/,
|
||||||
const bool /*use_all_edges*/) const override
|
const bool /*use_all_edges*/) const override
|
||||||
{
|
{
|
||||||
return {};
|
return {};
|
||||||
}
|
};
|
||||||
|
|
||||||
std::vector<engine::PhantomNodeWithDistance>
|
|
||||||
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>
|
std::vector<engine::PhantomNodeWithDistance>
|
||||||
NearestPhantomNodes(const util::Coordinate /*input_coordinate*/,
|
NearestPhantomNodes(const util::Coordinate /*input_coordinate*/,
|
||||||
const unsigned /*max_results*/,
|
const size_t /*max_results*/,
|
||||||
const double /*max_distance*/,
|
const boost::optional<double> /*max_distance*/,
|
||||||
const int /*bearing*/,
|
const boost::optional<engine::Bearing> /*bearing*/,
|
||||||
const int /*bearing_range*/,
|
|
||||||
const engine::Approach /*approach*/) const override
|
const engine::Approach /*approach*/) const override
|
||||||
{
|
{
|
||||||
return {};
|
return {};
|
||||||
}
|
};
|
||||||
|
|
||||||
std::vector<engine::PhantomNodeWithDistance>
|
engine::PhantomCandidateAlternatives NearestCandidatesWithAlternativeFromBigComponent(
|
||||||
NearestPhantomNodes(const util::Coordinate /*input_coordinate*/,
|
const util::Coordinate /*input_coordinate*/,
|
||||||
const unsigned /*max_results*/,
|
const boost::optional<double> /*max_distance*/,
|
||||||
const int /*bearing*/,
|
const boost::optional<engine::Bearing> /*bearing*/,
|
||||||
const int /*bearing_range*/,
|
const engine::Approach /*approach*/,
|
||||||
const engine::Approach /*approach*/) const override
|
const bool /*use_all_edges*/) const override
|
||||||
{
|
{
|
||||||
return {};
|
return {};
|
||||||
}
|
};
|
||||||
|
|
||||||
std::vector<engine::PhantomNodeWithDistance>
|
|
||||||
NearestPhantomNodes(const util::Coordinate /*input_coordinate*/,
|
|
||||||
const unsigned /*max_results*/,
|
|
||||||
const engine::Approach /*approach*/) const override
|
|
||||||
{
|
|
||||||
return {};
|
|
||||||
}
|
|
||||||
|
|
||||||
std::vector<engine::PhantomNodeWithDistance>
|
|
||||||
NearestPhantomNodes(const util::Coordinate /*input_coordinate*/,
|
|
||||||
const unsigned /*max_results*/,
|
|
||||||
const double /*max_distance*/,
|
|
||||||
const engine::Approach /*approach*/) const override
|
|
||||||
{
|
|
||||||
return {};
|
|
||||||
}
|
|
||||||
|
|
||||||
std::pair<engine::PhantomNode, engine::PhantomNode>
|
|
||||||
NearestPhantomNodeWithAlternativeFromBigComponent(const util::Coordinate /*input_coordinate*/,
|
|
||||||
const engine::Approach /*approach*/,
|
|
||||||
const bool /* use_all_edges */) const override
|
|
||||||
{
|
|
||||||
return {};
|
|
||||||
}
|
|
||||||
|
|
||||||
std::pair<engine::PhantomNode, engine::PhantomNode>
|
|
||||||
NearestPhantomNodeWithAlternativeFromBigComponent(const util::Coordinate /*input_coordinate*/,
|
|
||||||
const double /*max_distance*/,
|
|
||||||
const engine::Approach /*approach*/,
|
|
||||||
const bool /* use_all_edges */) const override
|
|
||||||
{
|
|
||||||
return {};
|
|
||||||
}
|
|
||||||
|
|
||||||
std::pair<engine::PhantomNode, engine::PhantomNode>
|
|
||||||
NearestPhantomNodeWithAlternativeFromBigComponent(const util::Coordinate /*input_coordinate*/,
|
|
||||||
const double /*max_distance*/,
|
|
||||||
const int /*bearing*/,
|
|
||||||
const int /*bearing_range*/,
|
|
||||||
const engine::Approach /*approach*/,
|
|
||||||
const bool /* use_all_edges */) const override
|
|
||||||
{
|
|
||||||
return {};
|
|
||||||
}
|
|
||||||
|
|
||||||
std::pair<engine::PhantomNode, engine::PhantomNode>
|
|
||||||
NearestPhantomNodeWithAlternativeFromBigComponent(const util::Coordinate /*input_coordinate*/,
|
|
||||||
const int /*bearing*/,
|
|
||||||
const int /*bearing_range*/,
|
|
||||||
const engine::Approach /*approach*/,
|
|
||||||
const bool /* use_all_edges */) const override
|
|
||||||
{
|
|
||||||
return {};
|
|
||||||
}
|
|
||||||
|
|
||||||
std::uint32_t GetCheckSum() const override { return 0; }
|
std::uint32_t GetCheckSum() const override { return 0; }
|
||||||
|
|
||||||
|
|||||||
@ -19,6 +19,20 @@
|
|||||||
#define CHECK_EQUAL_RANGE(R1, R2) \
|
#define CHECK_EQUAL_RANGE(R1, R2) \
|
||||||
BOOST_CHECK_EQUAL_COLLECTIONS((R1).begin(), (R1).end(), (R2).begin(), (R2).end());
|
BOOST_CHECK_EQUAL_COLLECTIONS((R1).begin(), (R1).end(), (R2).begin(), (R2).end());
|
||||||
|
|
||||||
|
#define CHECK_EQUAL_RANGE_OF_HINTS(R1, R2) \
|
||||||
|
BOOST_REQUIRE_EQUAL((R1).size(), (R2).size()); \
|
||||||
|
for (const auto i : util::irange<std::size_t>(0UL, (R1).size())) \
|
||||||
|
{ \
|
||||||
|
BOOST_REQUIRE(((R1)[i] && (R2)[i]) || !((R1)[i] || (R2)[i])); \
|
||||||
|
if ((R1)[i]) \
|
||||||
|
{ \
|
||||||
|
BOOST_CHECK_EQUAL_COLLECTIONS((R1)[i]->segment_hints.begin(), \
|
||||||
|
(R1)[i]->segment_hints.end(), \
|
||||||
|
(R2)[i]->segment_hints.begin(), \
|
||||||
|
(R2)[i]->segment_hints.end()); \
|
||||||
|
} \
|
||||||
|
}
|
||||||
|
|
||||||
BOOST_AUTO_TEST_SUITE(api_parameters_parser)
|
BOOST_AUTO_TEST_SUITE(api_parameters_parser)
|
||||||
|
|
||||||
using namespace osrm;
|
using namespace osrm;
|
||||||
@ -117,15 +131,16 @@ BOOST_AUTO_TEST_CASE(invalid_table_urls)
|
|||||||
// BOOST_CHECK_EQUAL(testInvalidOptions<TableParameters>("1,2;3,4?destinations=2"), 7UL);
|
// BOOST_CHECK_EQUAL(testInvalidOptions<TableParameters>("1,2;3,4?destinations=2"), 7UL);
|
||||||
}
|
}
|
||||||
|
|
||||||
BOOST_AUTO_TEST_CASE(valid_route_hint)
|
BOOST_AUTO_TEST_CASE(valid_route_segment_hint)
|
||||||
{
|
{
|
||||||
engine::PhantomNode reference_node;
|
engine::PhantomNode reference_node;
|
||||||
reference_node.input_location =
|
reference_node.input_location =
|
||||||
util::Coordinate(util::FloatLongitude{7.432251}, util::FloatLatitude{43.745995});
|
util::Coordinate(util::FloatLongitude{7.432251}, util::FloatLatitude{43.745995});
|
||||||
engine::Hint reference_hint{reference_node, 0x1337};
|
engine::SegmentHint reference_segment_hint{reference_node, 0x1337};
|
||||||
auto encoded_hint = reference_hint.ToBase64();
|
auto encoded_hint = reference_segment_hint.ToBase64();
|
||||||
auto hint = engine::Hint::FromBase64(encoded_hint);
|
auto seg_hint = engine::SegmentHint::FromBase64(encoded_hint);
|
||||||
BOOST_CHECK_EQUAL(hint.phantom.input_location, reference_hint.phantom.input_location);
|
BOOST_CHECK_EQUAL(seg_hint.phantom.input_location,
|
||||||
|
reference_segment_hint.phantom.input_location);
|
||||||
}
|
}
|
||||||
|
|
||||||
BOOST_AUTO_TEST_CASE(valid_route_urls)
|
BOOST_AUTO_TEST_CASE(valid_route_urls)
|
||||||
@ -147,7 +162,7 @@ BOOST_AUTO_TEST_CASE(valid_route_urls)
|
|||||||
CHECK_EQUAL_RANGE(reference_1.radiuses, result_1->radiuses);
|
CHECK_EQUAL_RANGE(reference_1.radiuses, result_1->radiuses);
|
||||||
CHECK_EQUAL_RANGE(reference_1.approaches, result_1->approaches);
|
CHECK_EQUAL_RANGE(reference_1.approaches, result_1->approaches);
|
||||||
CHECK_EQUAL_RANGE(reference_1.coordinates, result_1->coordinates);
|
CHECK_EQUAL_RANGE(reference_1.coordinates, result_1->coordinates);
|
||||||
CHECK_EQUAL_RANGE(reference_1.hints, result_1->hints);
|
CHECK_EQUAL_RANGE_OF_HINTS(reference_1.hints, result_1->hints);
|
||||||
|
|
||||||
RouteParameters reference_2{};
|
RouteParameters reference_2{};
|
||||||
reference_2.alternatives = true;
|
reference_2.alternatives = true;
|
||||||
@ -170,7 +185,7 @@ BOOST_AUTO_TEST_CASE(valid_route_urls)
|
|||||||
CHECK_EQUAL_RANGE(reference_2.radiuses, result_2->radiuses);
|
CHECK_EQUAL_RANGE(reference_2.radiuses, result_2->radiuses);
|
||||||
CHECK_EQUAL_RANGE(reference_2.approaches, result_2->approaches);
|
CHECK_EQUAL_RANGE(reference_2.approaches, result_2->approaches);
|
||||||
CHECK_EQUAL_RANGE(reference_2.coordinates, result_2->coordinates);
|
CHECK_EQUAL_RANGE(reference_2.coordinates, result_2->coordinates);
|
||||||
CHECK_EQUAL_RANGE(reference_2.hints, result_2->hints);
|
CHECK_EQUAL_RANGE_OF_HINTS(reference_2.hints, result_2->hints);
|
||||||
BOOST_CHECK_EQUAL(result_2->annotations_type == RouteParameters::AnnotationsType::All, true);
|
BOOST_CHECK_EQUAL(result_2->annotations_type == RouteParameters::AnnotationsType::All, true);
|
||||||
|
|
||||||
RouteParameters reference_3{false,
|
RouteParameters reference_3{false,
|
||||||
@ -195,14 +210,15 @@ BOOST_AUTO_TEST_CASE(valid_route_urls)
|
|||||||
CHECK_EQUAL_RANGE(reference_3.radiuses, result_3->radiuses);
|
CHECK_EQUAL_RANGE(reference_3.radiuses, result_3->radiuses);
|
||||||
CHECK_EQUAL_RANGE(reference_3.approaches, result_3->approaches);
|
CHECK_EQUAL_RANGE(reference_3.approaches, result_3->approaches);
|
||||||
CHECK_EQUAL_RANGE(reference_3.coordinates, result_3->coordinates);
|
CHECK_EQUAL_RANGE(reference_3.coordinates, result_3->coordinates);
|
||||||
CHECK_EQUAL_RANGE(reference_3.hints, result_3->hints);
|
CHECK_EQUAL_RANGE_OF_HINTS(reference_3.hints, result_3->hints);
|
||||||
|
|
||||||
engine::PhantomNode phantom_1;
|
engine::PhantomNode phantom_1;
|
||||||
phantom_1.input_location = coords_1[0];
|
phantom_1.input_location = coords_1[0];
|
||||||
engine::PhantomNode phantom_2;
|
engine::PhantomNode phantom_2;
|
||||||
phantom_2.input_location = coords_1[1];
|
phantom_2.input_location = coords_1[1];
|
||||||
std::vector<boost::optional<engine::Hint>> hints_4 = {engine::Hint{phantom_1, 0x1337},
|
std::vector<boost::optional<engine::Hint>> hints_4 = {
|
||||||
engine::Hint{phantom_2, 0x1337}};
|
engine::Hint{{engine::SegmentHint{phantom_1, 0x1337}}},
|
||||||
|
engine::Hint{{engine::SegmentHint{phantom_2, 0x1337}}}};
|
||||||
RouteParameters reference_4{false,
|
RouteParameters reference_4{false,
|
||||||
false,
|
false,
|
||||||
false,
|
false,
|
||||||
@ -226,7 +242,7 @@ BOOST_AUTO_TEST_CASE(valid_route_urls)
|
|||||||
CHECK_EQUAL_RANGE(reference_4.radiuses, result_4->radiuses);
|
CHECK_EQUAL_RANGE(reference_4.radiuses, result_4->radiuses);
|
||||||
CHECK_EQUAL_RANGE(reference_4.approaches, result_4->approaches);
|
CHECK_EQUAL_RANGE(reference_4.approaches, result_4->approaches);
|
||||||
CHECK_EQUAL_RANGE(reference_4.coordinates, result_4->coordinates);
|
CHECK_EQUAL_RANGE(reference_4.coordinates, result_4->coordinates);
|
||||||
CHECK_EQUAL_RANGE(reference_4.hints, result_4->hints);
|
CHECK_EQUAL_RANGE_OF_HINTS(reference_4.hints, result_4->hints);
|
||||||
|
|
||||||
std::vector<boost::optional<engine::Bearing>> bearings_4 = {
|
std::vector<boost::optional<engine::Bearing>> bearings_4 = {
|
||||||
boost::none,
|
boost::none,
|
||||||
@ -255,7 +271,7 @@ BOOST_AUTO_TEST_CASE(valid_route_urls)
|
|||||||
CHECK_EQUAL_RANGE(reference_5.radiuses, result_5->radiuses);
|
CHECK_EQUAL_RANGE(reference_5.radiuses, result_5->radiuses);
|
||||||
CHECK_EQUAL_RANGE(reference_5.approaches, result_5->approaches);
|
CHECK_EQUAL_RANGE(reference_5.approaches, result_5->approaches);
|
||||||
CHECK_EQUAL_RANGE(reference_5.coordinates, result_5->coordinates);
|
CHECK_EQUAL_RANGE(reference_5.coordinates, result_5->coordinates);
|
||||||
CHECK_EQUAL_RANGE(reference_5.hints, result_5->hints);
|
CHECK_EQUAL_RANGE_OF_HINTS(reference_5.hints, result_5->hints);
|
||||||
|
|
||||||
std::vector<util::Coordinate> coords_2 = {{util::FloatLongitude{0}, util::FloatLatitude{1}},
|
std::vector<util::Coordinate> coords_2 = {{util::FloatLongitude{0}, util::FloatLatitude{1}},
|
||||||
{util::FloatLongitude{2}, util::FloatLatitude{3}},
|
{util::FloatLongitude{2}, util::FloatLatitude{3}},
|
||||||
@ -275,7 +291,7 @@ BOOST_AUTO_TEST_CASE(valid_route_urls)
|
|||||||
CHECK_EQUAL_RANGE(reference_6.radiuses, result_6->radiuses);
|
CHECK_EQUAL_RANGE(reference_6.radiuses, result_6->radiuses);
|
||||||
CHECK_EQUAL_RANGE(reference_6.approaches, result_6->approaches);
|
CHECK_EQUAL_RANGE(reference_6.approaches, result_6->approaches);
|
||||||
CHECK_EQUAL_RANGE(reference_6.coordinates, result_6->coordinates);
|
CHECK_EQUAL_RANGE(reference_6.coordinates, result_6->coordinates);
|
||||||
CHECK_EQUAL_RANGE(reference_6.hints, result_6->hints);
|
CHECK_EQUAL_RANGE_OF_HINTS(reference_6.hints, result_6->hints);
|
||||||
|
|
||||||
auto result_7 = parseParameters<RouteParameters>("1,2;3,4?radiuses=;unlimited");
|
auto result_7 = parseParameters<RouteParameters>("1,2;3,4?radiuses=;unlimited");
|
||||||
RouteParameters reference_7{};
|
RouteParameters reference_7{};
|
||||||
@ -293,7 +309,7 @@ BOOST_AUTO_TEST_CASE(valid_route_urls)
|
|||||||
CHECK_EQUAL_RANGE(reference_7.radiuses, result_7->radiuses);
|
CHECK_EQUAL_RANGE(reference_7.radiuses, result_7->radiuses);
|
||||||
CHECK_EQUAL_RANGE(reference_7.approaches, result_7->approaches);
|
CHECK_EQUAL_RANGE(reference_7.approaches, result_7->approaches);
|
||||||
CHECK_EQUAL_RANGE(reference_7.coordinates, result_7->coordinates);
|
CHECK_EQUAL_RANGE(reference_7.coordinates, result_7->coordinates);
|
||||||
CHECK_EQUAL_RANGE(reference_7.hints, result_7->hints);
|
CHECK_EQUAL_RANGE_OF_HINTS(reference_7.hints, result_7->hints);
|
||||||
|
|
||||||
auto result_8 = parseParameters<RouteParameters>("1,2;3,4?radiuses=;");
|
auto result_8 = parseParameters<RouteParameters>("1,2;3,4?radiuses=;");
|
||||||
RouteParameters reference_8{};
|
RouteParameters reference_8{};
|
||||||
@ -320,7 +336,10 @@ BOOST_AUTO_TEST_CASE(valid_route_urls)
|
|||||||
engine::PhantomNode phantom_4;
|
engine::PhantomNode phantom_4;
|
||||||
phantom_4.input_location = coords_3[2];
|
phantom_4.input_location = coords_3[2];
|
||||||
std::vector<boost::optional<engine::Hint>> hints_10 = {
|
std::vector<boost::optional<engine::Hint>> hints_10 = {
|
||||||
engine::Hint{phantom_3, 0x1337}, boost::none, engine::Hint{phantom_4, 0x1337}, boost::none};
|
engine::Hint{{engine::SegmentHint{phantom_3, 0x1337}}},
|
||||||
|
{},
|
||||||
|
engine::Hint{{engine::SegmentHint{phantom_4, 0x1337}}},
|
||||||
|
{}};
|
||||||
|
|
||||||
RouteParameters reference_10{false,
|
RouteParameters reference_10{false,
|
||||||
false,
|
false,
|
||||||
@ -346,7 +365,7 @@ BOOST_AUTO_TEST_CASE(valid_route_urls)
|
|||||||
CHECK_EQUAL_RANGE(reference_10.radiuses, result_10->radiuses);
|
CHECK_EQUAL_RANGE(reference_10.radiuses, result_10->radiuses);
|
||||||
CHECK_EQUAL_RANGE(reference_10.approaches, result_10->approaches);
|
CHECK_EQUAL_RANGE(reference_10.approaches, result_10->approaches);
|
||||||
CHECK_EQUAL_RANGE(reference_10.coordinates, result_10->coordinates);
|
CHECK_EQUAL_RANGE(reference_10.coordinates, result_10->coordinates);
|
||||||
CHECK_EQUAL_RANGE(reference_10.hints, result_10->hints);
|
CHECK_EQUAL_RANGE_OF_HINTS(reference_10.hints, result_10->hints);
|
||||||
|
|
||||||
// Do not generate Hints when they are explicitly disabled
|
// Do not generate Hints when they are explicitly disabled
|
||||||
auto result_11 = parseParameters<RouteParameters>("1,2;3,4?generate_hints=false");
|
auto result_11 = parseParameters<RouteParameters>("1,2;3,4?generate_hints=false");
|
||||||
@ -459,7 +478,7 @@ BOOST_AUTO_TEST_CASE(valid_route_urls)
|
|||||||
CHECK_EQUAL_RANGE(reference_18.radiuses, result_18->radiuses);
|
CHECK_EQUAL_RANGE(reference_18.radiuses, result_18->radiuses);
|
||||||
CHECK_EQUAL_RANGE(reference_18.approaches, result_18->approaches);
|
CHECK_EQUAL_RANGE(reference_18.approaches, result_18->approaches);
|
||||||
CHECK_EQUAL_RANGE(reference_18.coordinates, result_18->coordinates);
|
CHECK_EQUAL_RANGE(reference_18.coordinates, result_18->coordinates);
|
||||||
CHECK_EQUAL_RANGE(reference_18.hints, result_18->hints);
|
CHECK_EQUAL_RANGE_OF_HINTS(reference_18.hints, result_18->hints);
|
||||||
|
|
||||||
RouteParameters reference_19{};
|
RouteParameters reference_19{};
|
||||||
reference_19.alternatives = true;
|
reference_19.alternatives = true;
|
||||||
@ -478,7 +497,7 @@ BOOST_AUTO_TEST_CASE(valid_route_urls)
|
|||||||
CHECK_EQUAL_RANGE(reference_19.radiuses, result_19->radiuses);
|
CHECK_EQUAL_RANGE(reference_19.radiuses, result_19->radiuses);
|
||||||
CHECK_EQUAL_RANGE(reference_19.approaches, result_19->approaches);
|
CHECK_EQUAL_RANGE(reference_19.approaches, result_19->approaches);
|
||||||
CHECK_EQUAL_RANGE(reference_19.coordinates, result_19->coordinates);
|
CHECK_EQUAL_RANGE(reference_19.coordinates, result_19->coordinates);
|
||||||
CHECK_EQUAL_RANGE(reference_19.hints, result_19->hints);
|
CHECK_EQUAL_RANGE_OF_HINTS(reference_19.hints, result_19->hints);
|
||||||
|
|
||||||
RouteParameters reference_20{};
|
RouteParameters reference_20{};
|
||||||
reference_20.alternatives = false;
|
reference_20.alternatives = false;
|
||||||
@ -497,7 +516,7 @@ BOOST_AUTO_TEST_CASE(valid_route_urls)
|
|||||||
CHECK_EQUAL_RANGE(reference_20.radiuses, result_20->radiuses);
|
CHECK_EQUAL_RANGE(reference_20.radiuses, result_20->radiuses);
|
||||||
CHECK_EQUAL_RANGE(reference_20.approaches, result_20->approaches);
|
CHECK_EQUAL_RANGE(reference_20.approaches, result_20->approaches);
|
||||||
CHECK_EQUAL_RANGE(reference_20.coordinates, result_20->coordinates);
|
CHECK_EQUAL_RANGE(reference_20.coordinates, result_20->coordinates);
|
||||||
CHECK_EQUAL_RANGE(reference_20.hints, result_20->hints);
|
CHECK_EQUAL_RANGE_OF_HINTS(reference_20.hints, result_20->hints);
|
||||||
|
|
||||||
// exclude flags
|
// exclude flags
|
||||||
RouteParameters reference_21{};
|
RouteParameters reference_21{};
|
||||||
@ -516,7 +535,7 @@ BOOST_AUTO_TEST_CASE(valid_route_urls)
|
|||||||
CHECK_EQUAL_RANGE(reference_21.radiuses, result_21->radiuses);
|
CHECK_EQUAL_RANGE(reference_21.radiuses, result_21->radiuses);
|
||||||
CHECK_EQUAL_RANGE(reference_21.approaches, result_21->approaches);
|
CHECK_EQUAL_RANGE(reference_21.approaches, result_21->approaches);
|
||||||
CHECK_EQUAL_RANGE(reference_21.coordinates, result_21->coordinates);
|
CHECK_EQUAL_RANGE(reference_21.coordinates, result_21->coordinates);
|
||||||
CHECK_EQUAL_RANGE(reference_21.hints, result_21->hints);
|
CHECK_EQUAL_RANGE_OF_HINTS(reference_21.hints, result_21->hints);
|
||||||
CHECK_EQUAL_RANGE(reference_21.exclude, result_21->exclude);
|
CHECK_EQUAL_RANGE(reference_21.exclude, result_21->exclude);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@ -200,8 +200,8 @@ void simple_verify_rtree(RTreeT &rtree,
|
|||||||
auto result_u = rtree.Nearest(pu, 1);
|
auto result_u = rtree.Nearest(pu, 1);
|
||||||
auto result_v = rtree.Nearest(pv, 1);
|
auto result_v = rtree.Nearest(pv, 1);
|
||||||
BOOST_CHECK(result_u.size() == 1 && result_v.size() == 1);
|
BOOST_CHECK(result_u.size() == 1 && result_v.size() == 1);
|
||||||
BOOST_CHECK(result_u.front().u == e.u || result_u.front().v == e.u);
|
BOOST_CHECK(result_u.front().data.u == e.u || result_u.front().data.v == e.u);
|
||||||
BOOST_CHECK(result_v.front().u == e.v || result_v.front().v == e.v);
|
BOOST_CHECK(result_v.front().data.u == e.v || result_v.front().data.v == e.v);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -226,8 +226,8 @@ void sampling_verify_rtree(RTreeT &rtree,
|
|||||||
auto result_lsnn = lsnn.Nearest(q, 1);
|
auto result_lsnn = lsnn.Nearest(q, 1);
|
||||||
BOOST_CHECK(result_rtree.size() == 1);
|
BOOST_CHECK(result_rtree.size() == 1);
|
||||||
BOOST_CHECK(result_lsnn.size() == 1);
|
BOOST_CHECK(result_lsnn.size() == 1);
|
||||||
auto rtree_u = result_rtree.back().u;
|
auto rtree_u = result_rtree.back().data.u;
|
||||||
auto rtree_v = result_rtree.back().v;
|
auto rtree_v = result_rtree.back().data.v;
|
||||||
auto lsnn_u = result_lsnn.back().u;
|
auto lsnn_u = result_lsnn.back().u;
|
||||||
auto lsnn_v = result_lsnn.back().v;
|
auto lsnn_v = result_lsnn.back().v;
|
||||||
|
|
||||||
@ -322,8 +322,8 @@ BOOST_AUTO_TEST_CASE(regression_test)
|
|||||||
BOOST_CHECK(result_rtree.size() == 1);
|
BOOST_CHECK(result_rtree.size() == 1);
|
||||||
BOOST_CHECK(result_ls.size() == 1);
|
BOOST_CHECK(result_ls.size() == 1);
|
||||||
|
|
||||||
BOOST_CHECK_EQUAL(result_ls.front().u, result_rtree.front().u);
|
BOOST_CHECK_EQUAL(result_ls.front().u, result_rtree.front().data.u);
|
||||||
BOOST_CHECK_EQUAL(result_ls.front().v, result_rtree.front().v);
|
BOOST_CHECK_EQUAL(result_ls.front().v, result_rtree.front().data.v);
|
||||||
}
|
}
|
||||||
|
|
||||||
// Bug: If you querry a point with a narrow radius, no result should be returned
|
// Bug: If you querry a point with a narrow radius, no result should be returned
|
||||||
@ -347,8 +347,8 @@ BOOST_AUTO_TEST_CASE(radius_regression_test)
|
|||||||
Coordinate input(FloatLongitude{5.2}, FloatLatitude{5.0});
|
Coordinate input(FloatLongitude{5.2}, FloatLatitude{5.0});
|
||||||
|
|
||||||
{
|
{
|
||||||
auto results = query.NearestPhantomNodesInRange(
|
auto results = query.NearestPhantomNodes(
|
||||||
input, 0.01, osrm::engine::Approach::UNRESTRICTED, true);
|
input, osrm::engine::Approach::UNRESTRICTED, boost::none, 0.01, boost::none, true);
|
||||||
BOOST_CHECK_EQUAL(results.size(), 0);
|
BOOST_CHECK_EQUAL(results.size(), 0);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -373,14 +373,14 @@ BOOST_AUTO_TEST_CASE(permissive_edge_snapping)
|
|||||||
Coordinate input(FloatLongitude{0.0005}, FloatLatitude{0.0005});
|
Coordinate input(FloatLongitude{0.0005}, FloatLatitude{0.0005});
|
||||||
|
|
||||||
{
|
{
|
||||||
auto results = query.NearestPhantomNodesInRange(
|
auto results = query.NearestPhantomNodes(
|
||||||
input, 1000, osrm::engine::Approach::UNRESTRICTED, false);
|
input, osrm::engine::Approach::UNRESTRICTED, boost::none, 1000, boost::none, false);
|
||||||
BOOST_CHECK_EQUAL(results.size(), 1);
|
BOOST_CHECK_EQUAL(results.size(), 1);
|
||||||
}
|
}
|
||||||
|
|
||||||
{
|
{
|
||||||
auto results = query.NearestPhantomNodesInRange(
|
auto results = query.NearestPhantomNodes(
|
||||||
input, 1000, osrm::engine::Approach::UNRESTRICTED, true);
|
input, osrm::engine::Approach::UNRESTRICTED, boost::none, 1000, boost::none, true);
|
||||||
BOOST_CHECK_EQUAL(results.size(), 2);
|
BOOST_CHECK_EQUAL(results.size(), 2);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -405,21 +405,30 @@ BOOST_AUTO_TEST_CASE(bearing_tests)
|
|||||||
Coordinate input(FloatLongitude{5.1}, FloatLatitude{5.0});
|
Coordinate input(FloatLongitude{5.1}, FloatLatitude{5.0});
|
||||||
|
|
||||||
{
|
{
|
||||||
auto results = query.NearestPhantomNodes(input, 5, osrm::engine::Approach::UNRESTRICTED);
|
auto results = query.NearestPhantomNodes(
|
||||||
|
input, osrm::engine::Approach::UNRESTRICTED, 5, boost::none, boost::none, false);
|
||||||
BOOST_CHECK_EQUAL(results.size(), 2);
|
BOOST_CHECK_EQUAL(results.size(), 2);
|
||||||
BOOST_CHECK_EQUAL(results.back().phantom_node.forward_segment_id.id, 0);
|
BOOST_CHECK_EQUAL(results.back().phantom_node.forward_segment_id.id, 0);
|
||||||
BOOST_CHECK_EQUAL(results.back().phantom_node.reverse_segment_id.id, 1);
|
BOOST_CHECK_EQUAL(results.back().phantom_node.reverse_segment_id.id, 1);
|
||||||
}
|
}
|
||||||
|
|
||||||
{
|
{
|
||||||
auto results =
|
auto results = query.NearestPhantomNodes(input,
|
||||||
query.NearestPhantomNodes(input, 5, 270, 10, osrm::engine::Approach::UNRESTRICTED);
|
osrm::engine::Approach::UNRESTRICTED,
|
||||||
|
5,
|
||||||
|
boost::none,
|
||||||
|
engine::Bearing{270, 10},
|
||||||
|
false);
|
||||||
BOOST_CHECK_EQUAL(results.size(), 0);
|
BOOST_CHECK_EQUAL(results.size(), 0);
|
||||||
}
|
}
|
||||||
|
|
||||||
{
|
{
|
||||||
auto results =
|
auto results = query.NearestPhantomNodes(input,
|
||||||
query.NearestPhantomNodes(input, 5, 45, 10, osrm::engine::Approach::UNRESTRICTED);
|
osrm::engine::Approach::UNRESTRICTED,
|
||||||
|
5,
|
||||||
|
boost::none,
|
||||||
|
engine::Bearing{45, 10},
|
||||||
|
false);
|
||||||
BOOST_CHECK_EQUAL(results.size(), 2);
|
BOOST_CHECK_EQUAL(results.size(), 2);
|
||||||
|
|
||||||
BOOST_CHECK(results[0].phantom_node.forward_segment_id.enabled);
|
BOOST_CHECK(results[0].phantom_node.forward_segment_id.enabled);
|
||||||
@ -432,20 +441,28 @@ BOOST_AUTO_TEST_CASE(bearing_tests)
|
|||||||
}
|
}
|
||||||
|
|
||||||
{
|
{
|
||||||
auto results = query.NearestPhantomNodesInRange(
|
auto results = query.NearestPhantomNodes(
|
||||||
input, 11000, osrm::engine::Approach::UNRESTRICTED, true);
|
input, osrm::engine::Approach::UNRESTRICTED, boost::none, 11000, boost::none, true);
|
||||||
BOOST_CHECK_EQUAL(results.size(), 2);
|
BOOST_CHECK_EQUAL(results.size(), 2);
|
||||||
}
|
}
|
||||||
|
|
||||||
{
|
{
|
||||||
auto results = query.NearestPhantomNodesInRange(
|
auto results = query.NearestPhantomNodes(input,
|
||||||
input, 11000, 270, 10, osrm::engine::Approach::UNRESTRICTED, true);
|
osrm::engine::Approach::UNRESTRICTED,
|
||||||
|
boost::none,
|
||||||
|
11000,
|
||||||
|
engine::Bearing{270, 10},
|
||||||
|
true);
|
||||||
BOOST_CHECK_EQUAL(results.size(), 0);
|
BOOST_CHECK_EQUAL(results.size(), 0);
|
||||||
}
|
}
|
||||||
|
|
||||||
{
|
{
|
||||||
auto results = query.NearestPhantomNodesInRange(
|
auto results = query.NearestPhantomNodes(input,
|
||||||
input, 11000, 45, 10, osrm::engine::Approach::UNRESTRICTED, true);
|
osrm::engine::Approach::UNRESTRICTED,
|
||||||
|
boost::none,
|
||||||
|
11000,
|
||||||
|
engine::Bearing{45, 10},
|
||||||
|
true);
|
||||||
BOOST_CHECK_EQUAL(results.size(), 2);
|
BOOST_CHECK_EQUAL(results.size(), 2);
|
||||||
|
|
||||||
BOOST_CHECK(results[0].phantom_node.forward_segment_id.enabled);
|
BOOST_CHECK(results[0].phantom_node.forward_segment_id.enabled);
|
||||||
|
|||||||
Loading…
Reference in New Issue
Block a user