96 break |
96 break |
97 # ja siirry seuraavaan päivään. |
97 # ja siirry seuraavaan päivään. |
98 date += timedelta(1) |
98 date += timedelta(1) |
99 # Typistä lopputulos haluttuun tulosmäärään. |
99 # Typistä lopputulos haluttuun tulosmäärään. |
100 return result[:max_amount] |
100 return result[:max_amount] |
101 def schedule_for_day(self, date, *, arrivals = False): |
101 def schedule_for_day(self, date, *, arrivals = False, allow_gone = False): |
102 ''' |
102 ''' |
103 Hakee pysäkin aikataulut tiettynä päivänä. |
103 Hakee pysäkin aikataulut tiettynä päivänä. |
104 ''' |
104 ''' |
105 # Jos päädyttiin aikataulukalenterin ulkopuolelle, niin tuotetaan virhe. Jos vain |
105 # Jos päädyttiin aikataulukalenterin ulkopuolelle, niin tuotetaan virhe. Jos vain |
106 # palautettaisiin tyhjä result, niin algoritmi jatkaisi etsintää loputtomiin. |
106 # palautettaisiin tyhjä result, niin algoritmi jatkaisi etsintää loputtomiin. |
115 # päätepysäkille, |
115 # päätepysäkille, |
116 stop = trip.contains_stop(self) |
116 stop = trip.contains_stop(self) |
117 if stop and (arrivals or not stop.is_arrival) and stop is not trip.schedule[-1]: |
117 if stop and (arrivals or not stop.is_arrival) and stop is not trip.schedule[-1]: |
118 # ja jos tämä halt on tulevaisuudessa, |
118 # ja jos tämä halt on tulevaisuudessa, |
119 stop_time = datetime.combine(date, time()) + stop.departure_time |
119 stop_time = datetime.combine(date, time()) + stop.departure_time |
120 if stop_time + timedelta(minutes = 1) >= now(): |
120 if allow_gone or (stop_time + timedelta(minutes = 1) >= now()): |
121 # lisää halt listaan. |
121 # lisää halt listaan. |
122 result.append({ |
122 result.append({ |
123 'date': date, |
123 'date': date, |
124 'offset': stop.departure_time, |
124 'offset': stop.departure_time, |
125 'time': stop_time, |
125 'time': stop_time, |
179 route = self.trip.concise_schedule(self), |
179 route = self.trip.concise_schedule(self), |
180 trip_length = self.trip.length - self.traveled_distance, |
180 trip_length = self.trip.length - self.traveled_distance, |
181 long = long, |
181 long = long, |
182 ) |
182 ) |
183 |
183 |
|
184 class BusStopCluster: |
|
185 def __init__(self): |
|
186 self.stops = set() |
|
187 self.cached_center = None |
|
188 self.name = None |
|
189 @property |
|
190 def url_name(self): |
|
191 return self.name.lower().replace('(', '').replace(')', '').replace(' ', '-') |
|
192 def add_stop(self, stop): |
|
193 assert not stop.cluster |
|
194 stop.cluster = self |
|
195 self.stops.add(stop) |
|
196 self.cached_center = None |
|
197 @property |
|
198 def center(self): |
|
199 if not self.cached_center: |
|
200 if self.stops: |
|
201 from statistics import median |
|
202 pointtype = type(next(iter(self.stops)).location) |
|
203 self.cached_center = pointtype( |
|
204 median(stop.location.x for stop in self.stops), |
|
205 median(stop.location.y for stop in self.stops), |
|
206 ) |
|
207 else: |
|
208 raise ValueError('an empty cluster has no center point') |
|
209 return self.cached_center |
|
210 def merge(self, other): |
|
211 for bus_stop in other.stops: |
|
212 bus_stop.cluster = self |
|
213 self.stops |= other.stops |
|
214 other.stops = set() |
|
215 other.cached_center = None |
|
216 def schedule(self, *, max_amount = 50): |
|
217 result = [] |
|
218 for stop in self.stops: |
|
219 result += stop.schedule(max_amount = max_amount) |
|
220 result.sort(key = lambda schedule_entry: schedule_entry['time']) |
|
221 return result[:max_amount] |
|
222 |
|
223 class CustomBusStopCluster(BusStopCluster): |
|
224 def __init__(self, *, name, stops): |
|
225 super().__init__() |
|
226 self.name = name |
|
227 self.stops = stops |
|
228 def add_stop(self, stop): |
|
229 return NotImplemented |
|
230 @property |
|
231 def url_name(self): |
|
232 from urllib.request import quote |
|
233 return 'custom?stops=' + ';'.join(stop.code for stop in self.stops) + '&name=' + quote(self.name) |
|
234 |
184 routes = {} |
235 routes = {} |
185 routes_per_id = {} |
236 routes_per_id = {} |
186 all_trips = {} |
237 all_trips = {} |
187 services = {} |
238 services = {} |
188 bus_stops = {} |
239 bus_stops = {} |
317 pass |
368 pass |
318 for bus_stop in bus_stops.values(): |
369 for bus_stop in bus_stops.values(): |
319 if not hasattr(bus_stop, 'region'): |
370 if not hasattr(bus_stop, 'region'): |
320 bus_stop.region = None |
371 bus_stop.region = None |
321 print('%d stops' % len(bus_stops), file = stderr) |
372 print('%d stops' % len(bus_stops), file = stderr) |
322 |
|
323 class BusStopCluster: |
|
324 def __init__(self): |
|
325 self.stops = set() |
|
326 self.cached_center = None |
|
327 self.name = None |
|
328 @property |
|
329 def url_name(self): |
|
330 return self.name.lower().replace('(', '').replace(')', '').replace(' ', '-') |
|
331 def add_stop(self, stop): |
|
332 assert not stop.cluster |
|
333 stop.cluster = self |
|
334 self.stops.add(stop) |
|
335 self.cached_center = None |
|
336 @property |
|
337 def center(self): |
|
338 if not self.cached_center: |
|
339 if self.stops: |
|
340 from statistics import median |
|
341 pointtype = type(next(iter(self.stops)).location) |
|
342 self.cached_center = pointtype( |
|
343 median(stop.location.x for stop in self.stops), |
|
344 median(stop.location.y for stop in self.stops), |
|
345 ) |
|
346 else: |
|
347 raise ValueError('an empty cluster has no center point') |
|
348 return self.cached_center |
|
349 def merge(self, other): |
|
350 for bus_stop in other.stops: |
|
351 bus_stop.cluster = self |
|
352 self.stops |= other.stops |
|
353 other.stops = set() |
|
354 other.cached_center = None |
|
355 def schedule(self, *, max_amount = 50): |
|
356 result = [] |
|
357 for stop in self.stops: |
|
358 result += stop.schedule(max_amount = max_amount) |
|
359 result.sort(key = lambda schedule_entry: schedule_entry['time']) |
|
360 return result[:max_amount] |
|
361 |
373 |
362 from collections import defaultdict |
374 from collections import defaultdict |
363 bus_stops_by_name = defaultdict(set) |
375 bus_stops_by_name = defaultdict(set) |
364 for bus_stop in bus_stops.values(): |
376 for bus_stop in bus_stops.values(): |
365 bus_stops_by_name[bus_stop.name].add(bus_stop) |
377 bus_stops_by_name[bus_stop.name].add(bus_stop) |