-
Notifications
You must be signed in to change notification settings - Fork 24
/
google_routing.jl
206 lines (177 loc) · 8.01 KB
/
google_routing.jl
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
#############################
### Google routing module ###
#############################
"""
Dictionary for Google Distances API requests:
**Keys**
* `:url` : url for google API, only JSON files outputs are accepted
* `:mode` : transportation mode used in simulation, in the current library scope only driving is accepted
* `:avoid` : map features to avoid (to mantain compatibility with OSM routes ferries should be avoided)
* `:units` : unit system for displaing distances (changing to *imperial* needs deeper changes in both OSMsim and OpenStreetMapX modules)
"""
const googleAPI_parameters = Dict{Symbol,String}(
:url => "https://maps.googleapis.com/maps/api/directions/json?",
:mode => "driving",
:avoid => "ferries",
:units => "metric",
)
"""
node_to_string(node_id::Int,map_data::MapData)
Convert node coordinates (stored in ENU system in the `nodes` field of `map_data`)
identified by `node_id` to string with LLA system coordinates
"""
function node_to_string(node_id::Int,map_data::MapData)
coords = LLA(map_data.nodes[node_id],map_data.bounds)
return string(coords.lat,",",coords.lon)
end
"""
Gets Google Distances API request url with three points (origin, destination, waypoint between)
**Arguments**
* `origin` : unique node id
* `destination` : unique node id
* `waypoint` : unique node id
* `map_data` : `OpenStreetMapX.MapData` object
* `googleapi_key`: Goole API key
* `googleapi_parameters` : dictionary with assumptions about Google Distances API request
"""
function get_googleapi_url(origin::Int,destination::Int, waypoint::Int,
map_data::OpenStreetMapX.MapData, googleapi_key::String;
googleapi_parameters::Dict{Symbol,String} = OpenStreetMapX.googleAPI_parameters)
origin = OpenStreetMapX.node_to_string(origin, map_data)
destination = OpenStreetMapX.node_to_string(destination, map_data)
waypoint = OpenStreetMapX.node_to_string(waypoint, map_data)
return googleapi_parameters[:url]*"origin="*origin*"&destination="*destination*"&waypoints="*waypoint*
"&avoid="*googleapi_parameters[:avoid]*"&units="*googleapi_parameters[:units]*
"&mode="*googleapi_parameters[:mode]*"&key="*googleapi_key
end
"""
Gets Google Distances API request url with two points (origin and destination)
**Arguments**
* `origin` : unique node id
* `destination` : unique node id
* `map_data` : `OpenStreetMapX.MapData;` object
* `googleapi_key`: Google API key
* `googleapi_parameters` : dictionary with assumptions about Google Distances API request
"""
function get_googleapi_url(origin::Int,destination::Int,
map_data::OpenStreetMapX.MapData, googleapi_key::String;
googleapi_parameters::Dict{Symbol,String} = OpenStreetMapX.googleAPI_parameters)
origin = OpenStreetMapX.node_to_string(origin, map_data)
destination = OpenStreetMapX.node_to_string(destination, map_data)
return googleapi_parameters[:url]*"origin="*origin*"&destination="*destination*
"&avoid="*googleapi_parameters[:avoid]*"&units="*googleapi_parameters[:units]*
"&mode="*googleapi_parameters[:mode]*"&key="*googleapi_key
end
"""
Get JSON file from Google Distances API request and extract results
**Arguments**
* `url` : string with proper url
"""
function parse_google_url(url::String)
status, routes = nothing, nothing
res_json = JSON.parse(String(HTTP.get(url).body))
status, routes = res_json["status"], res_json["routes"]
return status, routes
end
"""
Extract route from Google API results
**Arguments**
* `routes` : dictionary with informations about the route
"""
function extract_google_route(routes::Dict)
res = Array{Tuple{Float64,Float64},1}[]
legs = routes["legs"]
for leg in legs
steps = leg["steps"]
for step in steps
push!(res,OpenStreetMapX.decode(step["polyline"]["points"]))
end
end
return vcat(res...)
end
"""
Match Google route with vertices of map network
**Arguments**
* `route` : array with LLA coordinates of crucial route points
* `map_data` : `OpenStreetMapX.MapData;` object
"""
function google_route_to_network(route::Array{Tuple{Float64,Float64},1},map_data::MapData)
route = [ENU(LLA(coords[1], coords[2]),map_data.bounds) for coords in route]
res = [nearest_node(map_data, route[1])]
index = 2
for i = 2:length(route)
node = OpenStreetMapX.nearest_node(map_data, route[i])
if node != res[index-1]
push!(res,node)
index += 1
end
end
return res
end
"""
get_google_route(origin::Int, destination::Int, waypoint::Int,
map_data:MapData, googleapi_key::String;
googleapi_parameters::Dict{Symbol,String} = googleAPI_parameters)
Get route from to based on Google Distances API with three points
(`origin`, `destination` and `waypoint` between)
on map `map_data` using Google API key `googleapi_key` with optional
Google Distances API request parameters `googleapi_parameters`.
"""
function get_google_route(origin::Int,destination::Int,waypoint::Int,
map_data::OpenStreetMapX.OpenStreetMapX.MapData, googleapi_key::String;
googleapi_parameters::Dict{Symbol,String} = googleAPI_parameters)
url = OpenStreetMapX.get_googleapi_url(origin, destination, waypoint,map_data,googleapi_key,googleapi_parameters = googleapi_parameters)
status, routes = OpenStreetMapX.parse_google_url(url)
if status == "OK"
route = OpenStreetMapX.extract_google_route(routes[1])
return OpenStreetMapX.google_route_to_network(route,map_data), "google"
elseif status =="ZERO_RESULTS"
return Int[], "google"
elseif status == "OVER_QUERY_LIMIT"
sleep(0.5)
return OpenStreetMapX.get_google_route(origin,destination,waypoint,map_data,googleapi_key,googleapi_parameters = googleapi_parameters)
else
#get route based on OSM routing
@warn "Google Distances API cannot get a proper results - route will be calculated with OSMSim Routing module"
if rand() < 0.5
route_nodes, distance, route_time = OpenStreetMapX.shortest_route(map_data, origin, waypoint, destination)
return route_nodes, "shortest"
else
route_nodes, distance, route_time = OpenStreetMapX.fastest_route(map_data, origin, waypoint, destination)
return route_nodes, "fastest"
end
end
end
"""
get_google_route(origin::Int, destination::Int,
map_data:MapData, googleapi_key::String;
googleapi_parameters::Dict{Symbol,String} = googleAPI_parameters)
Get route from to based on Google Distances API with two points (`origin` and `destination`)
on map `map_data` using Google API key `googleapi_key` with optional
Google Distances API request parameters `googleapi_parameters`.
"""
function get_google_route(origin::Int,destination::Int,
map_data::MapData,googleapi_key::String;
googleapi_parameters::Dict{Symbol,String} = googleAPI_parameters)
url = OpenStreetMapX.get_googleapi_url(origin, destination,map_data,googleapi_key,googleapi_parameters = googleapi_parameters)
status, routes = OpenStreetMapX.parse_google_url(url)
if status == "OK"
route = OpenStreetMapX.extract_google_route(routes[1])
return OpenStreetMapX.google_route_to_network(route,map_data), "google"
elseif status =="ZERO_RESULTS"
return Int[],"google"
elseif status == "OVER_QUERY_LIMIT"
sleep(0.5)
return OpenStreetMapX.get_google_route(origin,destination,map_data,googleapi_key,googleapi_parameters = googleapi_parameters)
else
#get route based on OSM routing
@warn "Google Distances API cannot get a proper results - route will be calculated with OSMSim Routing module"
if rand() < 0.5
route_nodes, distance, route_time = OpenStreetMapX.shortest_route(map_data, origin, destination)
return route_nodes, "shortest"
else
route_nodes, distance, route_time = OpenStreetMapX.fastest_route(map_data, origin, destination)
return route_nodes, "fastest"
end
end
end