31
31
import copy
32
32
from collections import namedtuple
33
33
from navitiacommon import response_pb2 , type_pb2
34
+ from jormungandr import app , cache
34
35
import itertools
35
36
import logging
36
37
from jormungandr .street_network .street_network import StreetNetworkPathType
59
60
"physical_mode:Metro" ,
60
61
)
61
62
63
+
62
64
# if `(physical_mode:A, physical_mode:B) in NO_ACCESS_POINTS_TRANSFER` then it means that a transfer
63
65
# where we get out of a vehicle of `physical_mode:A` and then get in a vehicle of `physical_mode:B`
64
66
# **will not** go through an access point
74
76
itertools .product (ACCESS_POINTS_PHYSICAL_MODES , NO_ACCESS_POINTS_PHYSICAL_MODES )
75
77
) | set (itertools .product (NO_ACCESS_POINTS_PHYSICAL_MODES , ACCESS_POINTS_PHYSICAL_MODES ))
76
78
77
-
78
79
TransferResult = namedtuple ('TransferResult' , ['direct_path' , 'origin' , 'destination' ])
79
80
80
81
82
+ class TransferPathArgs :
83
+ def __init__ (self , section , prev_section_mode , next_section_mode ):
84
+ self .prev_section_mode = prev_section_mode
85
+ self .next_section_mode = next_section_mode
86
+ self .section = section
87
+
88
+ def __repr__ (self ):
89
+ return "{origin}:{destination}:{prev_section_mode}:{next_section_mode}" .format (
90
+ origin = self .section .origin .uri ,
91
+ destination = self .section .destination .uri ,
92
+ prev_section_mode = self .prev_section_mode ,
93
+ next_section_mode = self .next_section_mode ,
94
+ )
95
+
96
+
81
97
class TransferPool (object ):
82
98
def __init__ (
83
99
self ,
84
100
future_manager ,
85
101
instance ,
86
102
request ,
87
103
request_id ,
104
+ pt_planner_name ,
88
105
):
89
106
self ._future_manager = future_manager
90
107
self ._instance = instance
@@ -93,6 +110,16 @@ def __init__(
93
110
self ._streetnetwork_service = self ._instance .get_street_network (FallbackModes .walking .name , request )
94
111
self ._transfers_future = dict ()
95
112
self ._logger = logging .getLogger (__name__ )
113
+ self ._pt_planner = self ._instance .get_pt_planner (pt_planner_name )
114
+
115
+ def __repr__ (self ):
116
+ return "{name}:{language}:{publication_date}" .format (
117
+ name = self ._instance .name , language = self .language , publication_date = self ._instance .publication_date
118
+ )
119
+
120
+ @property
121
+ def language (self ):
122
+ return self ._request .get ('language' , "en-US" )
96
123
97
124
def _make_sub_request_id (self , origin_uri , destination_uri ):
98
125
return "{}_transfer_{}_{}" .format (self ._request_id , origin_uri , destination_uri )
@@ -167,32 +194,27 @@ def _do_no_access_point_transfer(self, section):
167
194
def _aysnc_no_access_point_transfer (self , section ):
168
195
return self ._future_manager .create_future (self ._do_no_access_point_transfer , section )
169
196
170
- def _get_access_points (self , stop_point_uri , access_point_filter = lambda x : x ):
171
- sub_request_id = "{}_transfer_start_{}" .format (self ._request_id , stop_point_uri )
172
- stop_points = self ._instance .georef .get_stop_points_from_uri (stop_point_uri , sub_request_id , depth = 2 )
173
- if not stop_points :
174
- return None
175
-
176
- return [
177
- type_pb2 .PtObject (name = ap .name , uri = ap .uri , embedded_type = type_pb2 .ACCESS_POINT , access_point = ap )
178
- for ap in stop_points [0 ].access_points
179
- if access_point_filter (ap )
180
- ]
181
-
182
197
def get_underlying_access_points (self , section , prev_section_mode , next_section_mode ):
183
198
"""
184
199
find out based on with extremity of the section the access points are calculated and request the georef for
185
200
access_points of the underlying stop_point
186
201
return: access_points
187
202
"""
203
+
188
204
if prev_section_mode in ACCESS_POINTS_PHYSICAL_MODES :
189
- return self ._get_access_points (
190
- section .origin .uri , access_point_filter = lambda access_point : access_point .is_exit
205
+ sub_request_id = "{}_transfer_start_{}" .format (self ._request_id , section .origin .uri )
206
+ return self ._pt_planner .get_access_points (
207
+ section .origin ,
208
+ access_point_filter = lambda access_point : access_point .is_exit ,
209
+ request_id = sub_request_id ,
191
210
)
192
211
193
212
if next_section_mode in ACCESS_POINTS_PHYSICAL_MODES :
194
- return self ._get_access_points (
195
- section .destination .uri , access_point_filter = lambda access_point : access_point .is_entrance
213
+ sub_request_id = "{}_transfer_start_{}" .format (self ._request_id , section .destination .uri )
214
+ return self ._pt_planner .get_access_points (
215
+ section .destination ,
216
+ access_point_filter = lambda access_point : access_point .is_entrance ,
217
+ request_id = sub_request_id ,
196
218
)
197
219
198
220
return None
@@ -241,6 +263,7 @@ def determinate_the_best_access_point(routing_matrix, access_points):
241
263
return best_access_point
242
264
243
265
def _get_transfer_result (self , section , origin , destination ):
266
+
244
267
sub_request_id = self ._make_sub_request_id (origin .uri , destination .uri )
245
268
direct_path_type = StreetNetworkPathType .DIRECT
246
269
extremity = PeriodExtremity (section .end_date_time , False )
@@ -255,36 +278,48 @@ def _get_transfer_result(self, section, origin, destination):
255
278
sub_request_id ,
256
279
)
257
280
if direct_path and direct_path .journeys :
258
- return TransferResult (direct_path , origin , destination )
259
- return None
260
-
261
- def _do_access_point_transfer (self , section , prev_section_mode , next_section_mode ):
262
- access_points = self .get_underlying_access_points (section , prev_section_mode , next_section_mode )
281
+ return (
282
+ direct_path .SerializeToString (),
283
+ origin .SerializeToString (),
284
+ destination .SerializeToString (),
285
+ )
286
+ return None , None , None
287
+
288
+ @cache .memoize (app .config [str ('CACHE_CONFIGURATION' )].get (str ('TIMEOUT_TRANSFER_PATH' ), 24 * 60 * 60 ))
289
+ def get_cached_transfer_path (self , transfer_path_args ):
290
+ access_points = self .get_underlying_access_points (
291
+ transfer_path_args .section ,
292
+ transfer_path_args .prev_section_mode ,
293
+ transfer_path_args .next_section_mode ,
294
+ )
263
295
# if no access points are found for this stop point, which is supposed to have access points
264
296
# we do nothing about the transfer path
265
297
if not access_points :
266
- return None
298
+ return None , None , None
267
299
268
300
origins , destinations = self .determinate_matrix_entry (
269
- section , access_points , prev_section_mode , next_section_mode
301
+ transfer_path_args .section ,
302
+ access_points ,
303
+ transfer_path_args .prev_section_mode ,
304
+ transfer_path_args .next_section_mode ,
270
305
)
271
306
272
307
if len (origins ) > 1 and len (destinations ) > 1 :
273
308
self ._logger .error (
274
309
"Error occurred when computing transfer path both origin's and destination's sizes are larger than 1"
275
310
)
276
- return None
311
+ return None , None , None
277
312
278
313
if len (origins ) == 1 and len (destinations ) == 1 :
279
- return self ._get_transfer_result (section , origins [0 ], destinations [0 ])
314
+ return self ._get_transfer_result (transfer_path_args . section , origins [0 ], destinations [0 ])
280
315
281
316
sub_request_id = "{}_transfer_matrix" .format (self ._request_id )
282
317
routing_matrix = self ._streetnetwork_service .get_street_network_routing_matrix (
283
318
self ._instance ,
284
319
origins ,
285
320
destinations ,
286
321
FallbackModes .walking .name ,
287
- section .duration * 3 ,
322
+ transfer_path_args . section .duration * 3 ,
288
323
self ._request ,
289
324
sub_request_id ,
290
325
)
@@ -293,16 +328,36 @@ def _do_access_point_transfer(self, section, prev_section_mode, next_section_mod
293
328
matrix .routing_status == response_pb2 .unreached for matrix in routing_matrix .rows [0 ].routing_response
294
329
):
295
330
logging .getLogger (__name__ ).warning ("no access points is reachable in transfer path computation" )
296
- return None
331
+ return None , None , None
297
332
298
333
# now it's time to find the best combo
299
334
# (stop_point -> access_points or access_points -> stop_point)
300
335
best_access_point = self .determinate_the_best_access_point (routing_matrix , access_points )
301
336
302
337
origin , destination = self .determinate_direct_path_entry (
303
- section , best_access_point , prev_section_mode , next_section_mode
338
+ transfer_path_args .section ,
339
+ best_access_point ,
340
+ transfer_path_args .prev_section_mode ,
341
+ transfer_path_args .next_section_mode ,
304
342
)
305
- return self ._get_transfer_result (section , origin , destination )
343
+ return self ._get_transfer_result (transfer_path_args .section , origin , destination )
344
+
345
+ def _do_access_point_transfer (self , section , prev_section_mode , next_section_mode ):
346
+ path , origin , destination = self .get_cached_transfer_path (
347
+ TransferPathArgs (section , prev_section_mode , next_section_mode )
348
+ )
349
+ if not path :
350
+ return None
351
+ pb_path = response_pb2 .Response ()
352
+ pb_path .ParseFromString (path )
353
+
354
+ pb_origin = type_pb2 .PtObject ()
355
+ pb_origin .ParseFromString (origin )
356
+
357
+ pb_destination = type_pb2 .PtObject ()
358
+ pb_destination .ParseFromString (destination )
359
+
360
+ return TransferResult (pb_path , pb_origin , pb_destination )
306
361
307
362
def _aysnc_access_point_transfer (self , section , prev_section_mode , next_section_mode ):
308
363
return self ._future_manager .create_future (
@@ -351,22 +406,21 @@ def wait_and_complete(self, section):
351
406
352
407
# we assume here the transfer street network has only one section, which is in walking mode
353
408
transfer_street_network = transfer_direct_path .journeys [0 ].sections [0 ].street_network
354
- language = self ._request .get ('language' , "en-US" )
355
409
356
410
if self ._is_access_point (transfer_result .origin ):
357
411
prepend_path_item_with_access_point (
358
412
transfer_street_network .path_items ,
359
413
section .origin .stop_point ,
360
414
transfer_result .origin .access_point ,
361
- language ,
415
+ self . language ,
362
416
)
363
417
364
418
if self ._is_access_point (transfer_result .destination ):
365
419
append_path_item_with_access_point (
366
420
transfer_street_network .path_items ,
367
421
section .destination .stop_point ,
368
422
transfer_result .destination .access_point ,
369
- language ,
423
+ self . language ,
370
424
)
371
425
372
426
section .street_network .CopyFrom (transfer_street_network )
0 commit comments