Thu, 06 Dec 2018 19:35:38 +0200
bus live information
0 | 1 | #!/usr/bin/env python3 |
2 | 2 | import enum, json |
3 | from sys import stderr | |
0 | 4 | from datetime import date, time, datetime, timedelta |
5 | 5 | from copy import copy |
2 | 6 | from misc import * |
7
f3791dccfd03
Käännetty tiedostojen nimet englanniksi
Teemu Piippo <teemu@hecknology.net>
parents:
5
diff
changeset
|
7 | from geometry import * |
127 | 8 | import uuid |
0 | 9 | |
24
e6bdb9c54096
Yhtenäistetty ohjelmakoodin kieli englanniksi
Teemu Piippo <teemu@hecknology.net>
parents:
23
diff
changeset
|
10 | def transform_trip_reference(reference): |
e6bdb9c54096
Yhtenäistetty ohjelmakoodin kieli englanniksi
Teemu Piippo <teemu@hecknology.net>
parents:
23
diff
changeset
|
11 | return reference |
0 | 12 | |
24
e6bdb9c54096
Yhtenäistetty ohjelmakoodin kieli englanniksi
Teemu Piippo <teemu@hecknology.net>
parents:
23
diff
changeset
|
13 | class BusTrip: |
114 | 14 | def __init__(self, reference, route, service, length, block_id, shape): |
71
d2e19670b772
Remove assumptions and added some api stuff
Teemu Piippo <teemu@hecknology.net>
parents:
42
diff
changeset
|
15 | self.reference, self.route, self.service, self.block_id = reference, route, service, block_id |
22 | 16 | self.length = length |
24
e6bdb9c54096
Yhtenäistetty ohjelmakoodin kieli englanniksi
Teemu Piippo <teemu@hecknology.net>
parents:
23
diff
changeset
|
17 | self.schedule = [] |
e6bdb9c54096
Yhtenäistetty ohjelmakoodin kieli englanniksi
Teemu Piippo <teemu@hecknology.net>
parents:
23
diff
changeset
|
18 | self.name = transform_trip_reference(reference) |
114 | 19 | self.shape = str(shape) |
0 | 20 | def __repr__(self): |
24
e6bdb9c54096
Yhtenäistetty ohjelmakoodin kieli englanniksi
Teemu Piippo <teemu@hecknology.net>
parents:
23
diff
changeset
|
21 | return 'all_trips[%r]' % self.name |
e6bdb9c54096
Yhtenäistetty ohjelmakoodin kieli englanniksi
Teemu Piippo <teemu@hecknology.net>
parents:
23
diff
changeset
|
22 | def contains_stop(self, stop): |
e6bdb9c54096
Yhtenäistetty ohjelmakoodin kieli englanniksi
Teemu Piippo <teemu@hecknology.net>
parents:
23
diff
changeset
|
23 | for halt in self.schedule: |
e6bdb9c54096
Yhtenäistetty ohjelmakoodin kieli englanniksi
Teemu Piippo <teemu@hecknology.net>
parents:
23
diff
changeset
|
24 | if halt.stop is stop: |
e6bdb9c54096
Yhtenäistetty ohjelmakoodin kieli englanniksi
Teemu Piippo <teemu@hecknology.net>
parents:
23
diff
changeset
|
25 | return halt |
0 | 26 | else: |
27 | return None | |
24
e6bdb9c54096
Yhtenäistetty ohjelmakoodin kieli englanniksi
Teemu Piippo <teemu@hecknology.net>
parents:
23
diff
changeset
|
28 | def is_served_at(self, day): |
0 | 29 | try: |
24
e6bdb9c54096
Yhtenäistetty ohjelmakoodin kieli englanniksi
Teemu Piippo <teemu@hecknology.net>
parents:
23
diff
changeset
|
30 | return self.service in services_for_day[day] |
0 | 31 | except KeyError: |
32 | return False | |
24
e6bdb9c54096
Yhtenäistetty ohjelmakoodin kieli englanniksi
Teemu Piippo <teemu@hecknology.net>
parents:
23
diff
changeset
|
33 | def concise_schedule(self, starting_stop = None): |
72 | 34 | if starting_stop and starting_stop in self.schedule: |
35 | schedule = copy(self.schedule) | |
36 | schedule = schedule[schedule.index(starting_stop):] | |
37 | else: | |
38 | schedule = self.schedule | |
71
d2e19670b772
Remove assumptions and added some api stuff
Teemu Piippo <teemu@hecknology.net>
parents:
42
diff
changeset
|
39 | if profile['regions']['use-regions']: |
d2e19670b772
Remove assumptions and added some api stuff
Teemu Piippo <teemu@hecknology.net>
parents:
42
diff
changeset
|
40 | used_areas = set() |
d2e19670b772
Remove assumptions and added some api stuff
Teemu Piippo <teemu@hecknology.net>
parents:
42
diff
changeset
|
41 | result = [] |
d2e19670b772
Remove assumptions and added some api stuff
Teemu Piippo <teemu@hecknology.net>
parents:
42
diff
changeset
|
42 | for halt in schedule: |
d2e19670b772
Remove assumptions and added some api stuff
Teemu Piippo <teemu@hecknology.net>
parents:
42
diff
changeset
|
43 | stop = halt.stop |
d2e19670b772
Remove assumptions and added some api stuff
Teemu Piippo <teemu@hecknology.net>
parents:
42
diff
changeset
|
44 | if stop.region and stop.region not in used_areas: |
d2e19670b772
Remove assumptions and added some api stuff
Teemu Piippo <teemu@hecknology.net>
parents:
42
diff
changeset
|
45 | used_areas.add(stop.region) |
d2e19670b772
Remove assumptions and added some api stuff
Teemu Piippo <teemu@hecknology.net>
parents:
42
diff
changeset
|
46 | result.append(stop.region) |
d2e19670b772
Remove assumptions and added some api stuff
Teemu Piippo <teemu@hecknology.net>
parents:
42
diff
changeset
|
47 | return result |
5 | 48 | else: |
72 | 49 | return [halt.stop.name for halt in schedule] |
0 | 50 | |
24
e6bdb9c54096
Yhtenäistetty ohjelmakoodin kieli englanniksi
Teemu Piippo <teemu@hecknology.net>
parents:
23
diff
changeset
|
51 | class BusRoute: |
e6bdb9c54096
Yhtenäistetty ohjelmakoodin kieli englanniksi
Teemu Piippo <teemu@hecknology.net>
parents:
23
diff
changeset
|
52 | def __init__(self, entry): |
e6bdb9c54096
Yhtenäistetty ohjelmakoodin kieli englanniksi
Teemu Piippo <teemu@hecknology.net>
parents:
23
diff
changeset
|
53 | self.id = entry['route_id'] |
e6bdb9c54096
Yhtenäistetty ohjelmakoodin kieli englanniksi
Teemu Piippo <teemu@hecknology.net>
parents:
23
diff
changeset
|
54 | self.reference = entry['route_short_name'] |
28
670ffa424ded
Bussipysäkit tallentavat ajovuoronsa välimuistiin suoritusajan nopeuttamiseksi
Teemu Piippo <teemu@hecknology.net>
parents:
26
diff
changeset
|
55 | self.trips = set() |
90 | 56 | self.service = None |
0 | 57 | def __repr__(self): |
24
e6bdb9c54096
Yhtenäistetty ohjelmakoodin kieli englanniksi
Teemu Piippo <teemu@hecknology.net>
parents:
23
diff
changeset
|
58 | return 'routes[%r]' % self.reference |
0 | 59 | |
24
e6bdb9c54096
Yhtenäistetty ohjelmakoodin kieli englanniksi
Teemu Piippo <teemu@hecknology.net>
parents:
23
diff
changeset
|
60 | class BusService: |
e6bdb9c54096
Yhtenäistetty ohjelmakoodin kieli englanniksi
Teemu Piippo <teemu@hecknology.net>
parents:
23
diff
changeset
|
61 | def __init__(self, reference): |
e6bdb9c54096
Yhtenäistetty ohjelmakoodin kieli englanniksi
Teemu Piippo <teemu@hecknology.net>
parents:
23
diff
changeset
|
62 | self.reference = reference |
e6bdb9c54096
Yhtenäistetty ohjelmakoodin kieli englanniksi
Teemu Piippo <teemu@hecknology.net>
parents:
23
diff
changeset
|
63 | self.dates = set() |
0 | 64 | def __repr__(self): |
24
e6bdb9c54096
Yhtenäistetty ohjelmakoodin kieli englanniksi
Teemu Piippo <teemu@hecknology.net>
parents:
23
diff
changeset
|
65 | return 'services[%r]' % self.reference |
0 | 66 | |
24
e6bdb9c54096
Yhtenäistetty ohjelmakoodin kieli englanniksi
Teemu Piippo <teemu@hecknology.net>
parents:
23
diff
changeset
|
67 | class BusStop: |
29 | 68 | def __init__(self, reference, name, location, code = None): |
24
e6bdb9c54096
Yhtenäistetty ohjelmakoodin kieli englanniksi
Teemu Piippo <teemu@hecknology.net>
parents:
23
diff
changeset
|
69 | self.reference, self.name, self.location = reference, name, location |
29 | 70 | self.code = code or reference |
15
a22cdf28930f
Lisätty bussipysäkkien ryhmittely
Teemu Piippo <teemu@hecknology.net>
parents:
7
diff
changeset
|
71 | self.cluster = None |
a22cdf28930f
Lisätty bussipysäkkien ryhmittely
Teemu Piippo <teemu@hecknology.net>
parents:
7
diff
changeset
|
72 | self.pairs = set() # samannimiset lähellä olevat pysäkit |
28
670ffa424ded
Bussipysäkit tallentavat ajovuoronsa välimuistiin suoritusajan nopeuttamiseksi
Teemu Piippo <teemu@hecknology.net>
parents:
26
diff
changeset
|
73 | self.involved_trips = set() |
90 | 74 | self.services = set() |
0 | 75 | def __repr__(self): |
24
e6bdb9c54096
Yhtenäistetty ohjelmakoodin kieli englanniksi
Teemu Piippo <teemu@hecknology.net>
parents:
23
diff
changeset
|
76 | return 'bus_stops[%r]' % self.reference |
127 | 77 | def schedule(self, *, max_amount = 50, max_past = 0, arrivals = False): |
0 | 78 | ''' |
79 | Hakee tämän pysäkin seuraavat `määrä` lähtöä. Päätepysäkille saapuvia busseja ei | |
24
e6bdb9c54096
Yhtenäistetty ohjelmakoodin kieli englanniksi
Teemu Piippo <teemu@hecknology.net>
parents:
23
diff
changeset
|
80 | lasketa. Palauttaa pysähdykset listana jossa alkiot ovat muotoa (aika, halt), |
0 | 81 | jossa: |
82 | - `aika` on saapumishetki muotoa datetime ja | |
24
e6bdb9c54096
Yhtenäistetty ohjelmakoodin kieli englanniksi
Teemu Piippo <teemu@hecknology.net>
parents:
23
diff
changeset
|
83 | - `halt` on vastaava BusHalt olio. |
0 | 84 | |
85 | Mikäli pysäkille ei ole määrätty riittävästi pysähdyksiä kalenterissa, tuloslista | |
86 | jää alimittaiseksi, mahdollisesti jopa tyhjäksi. | |
87 | ''' | |
17
fa3c822859b5
Refaktorioitu aikatauluhaku
Teemu Piippo <teemu@hecknology.net>
parents:
15
diff
changeset
|
88 | result = [] |
20
3199e289ae62
- Sivusto hieman edustuksellisempi
Teemu Piippo <teemu@hecknology.net>
parents:
19
diff
changeset
|
89 | # -1 päivää yövuoroja varten |
24
e6bdb9c54096
Yhtenäistetty ohjelmakoodin kieli englanniksi
Teemu Piippo <teemu@hecknology.net>
parents:
23
diff
changeset
|
90 | date = today() - timedelta(days = 1) |
127 | 91 | gone_list = [] |
0 | 92 | # Niin kauan kuin aikatauluja ei ole vielä tarpeeksi, |
17
fa3c822859b5
Refaktorioitu aikatauluhaku
Teemu Piippo <teemu@hecknology.net>
parents:
15
diff
changeset
|
93 | while len(result) < max_amount: |
0 | 94 | try: |
95 | # hae nykyisen päivän aikataulut ja lisää ne, | |
127 | 96 | schedule = self.schedule_for_day(date, arrivals = arrivals, allow_gone = True) |
97 | for entry in schedule: | |
98 | if entry['gone']: | |
99 | gone_list.append(entry) | |
100 | else: | |
101 | result.append(entry) | |
17
fa3c822859b5
Refaktorioitu aikatauluhaku
Teemu Piippo <teemu@hecknology.net>
parents:
15
diff
changeset
|
102 | except ValueError: |
0 | 103 | # paitsi jos mentiin kalenterin ulkopuolelle, jolloin lopetetaan, |
104 | break | |
105 | # ja siirry seuraavaan päivään. | |
17
fa3c822859b5
Refaktorioitu aikatauluhaku
Teemu Piippo <teemu@hecknology.net>
parents:
15
diff
changeset
|
106 | date += timedelta(1) |
0 | 107 | # Typistä lopputulos haluttuun tulosmäärään. |
127 | 108 | if gone_list: |
109 | result = gone_list[-max_past:] + result | |
17
fa3c822859b5
Refaktorioitu aikatauluhaku
Teemu Piippo <teemu@hecknology.net>
parents:
15
diff
changeset
|
110 | return result[:max_amount] |
109 | 111 | def schedule_for_day(self, date, *, arrivals = False, allow_gone = False): |
17
fa3c822859b5
Refaktorioitu aikatauluhaku
Teemu Piippo <teemu@hecknology.net>
parents:
15
diff
changeset
|
112 | ''' |
fa3c822859b5
Refaktorioitu aikatauluhaku
Teemu Piippo <teemu@hecknology.net>
parents:
15
diff
changeset
|
113 | Hakee pysäkin aikataulut tiettynä päivänä. |
fa3c822859b5
Refaktorioitu aikatauluhaku
Teemu Piippo <teemu@hecknology.net>
parents:
15
diff
changeset
|
114 | ''' |
fa3c822859b5
Refaktorioitu aikatauluhaku
Teemu Piippo <teemu@hecknology.net>
parents:
15
diff
changeset
|
115 | # Jos päädyttiin aikataulukalenterin ulkopuolelle, niin tuotetaan virhe. Jos vain |
24
e6bdb9c54096
Yhtenäistetty ohjelmakoodin kieli englanniksi
Teemu Piippo <teemu@hecknology.net>
parents:
23
diff
changeset
|
116 | # palautettaisiin tyhjä result, niin algoritmi jatkaisi etsintää loputtomiin. |
17
fa3c822859b5
Refaktorioitu aikatauluhaku
Teemu Piippo <teemu@hecknology.net>
parents:
15
diff
changeset
|
117 | if date > viimeinen_käyttöpäivä: |
fa3c822859b5
Refaktorioitu aikatauluhaku
Teemu Piippo <teemu@hecknology.net>
parents:
15
diff
changeset
|
118 | raise ValueError('tried to retrieve schedule for date %s which is outside schedule data' % date) |
fa3c822859b5
Refaktorioitu aikatauluhaku
Teemu Piippo <teemu@hecknology.net>
parents:
15
diff
changeset
|
119 | result = [] |
fa3c822859b5
Refaktorioitu aikatauluhaku
Teemu Piippo <teemu@hecknology.net>
parents:
15
diff
changeset
|
120 | # Jokaiselle ajovuorolle, |
28
670ffa424ded
Bussipysäkit tallentavat ajovuoronsa välimuistiin suoritusajan nopeuttamiseksi
Teemu Piippo <teemu@hecknology.net>
parents:
26
diff
changeset
|
121 | for trip in self.involved_trips: |
17
fa3c822859b5
Refaktorioitu aikatauluhaku
Teemu Piippo <teemu@hecknology.net>
parents:
15
diff
changeset
|
122 | # jos tämä ajovuoro ajetaan tänä päivänä |
24
e6bdb9c54096
Yhtenäistetty ohjelmakoodin kieli englanniksi
Teemu Piippo <teemu@hecknology.net>
parents:
23
diff
changeset
|
123 | if trip.is_served_at(date): |
e6bdb9c54096
Yhtenäistetty ohjelmakoodin kieli englanniksi
Teemu Piippo <teemu@hecknology.net>
parents:
23
diff
changeset
|
124 | # ja jos tämä trip pysähtyy tällä pysäkillä, ei kuitenkaan saapuen |
17
fa3c822859b5
Refaktorioitu aikatauluhaku
Teemu Piippo <teemu@hecknology.net>
parents:
15
diff
changeset
|
125 | # päätepysäkille, |
24
e6bdb9c54096
Yhtenäistetty ohjelmakoodin kieli englanniksi
Teemu Piippo <teemu@hecknology.net>
parents:
23
diff
changeset
|
126 | stop = trip.contains_stop(self) |
31
60045b362d71
- Ajovuoroa ei enää esitetä kahdessa välilehdessä vaan puukuvaimessa
Teemu Piippo <teemu@hecknology.net>
parents:
30
diff
changeset
|
127 | if stop and (arrivals or not stop.is_arrival) and stop is not trip.schedule[-1]: |
24
e6bdb9c54096
Yhtenäistetty ohjelmakoodin kieli englanniksi
Teemu Piippo <teemu@hecknology.net>
parents:
23
diff
changeset
|
128 | # ja jos tämä halt on tulevaisuudessa, |
75 | 129 | stop_time = datetime.combine(date, time()) + stop.departure_time |
127 | 130 | gone = stop_time + timedelta(minutes = 1) < now() |
131 | if allow_gone or not gone: | |
24
e6bdb9c54096
Yhtenäistetty ohjelmakoodin kieli englanniksi
Teemu Piippo <teemu@hecknology.net>
parents:
23
diff
changeset
|
132 | # lisää halt listaan. |
18 | 133 | result.append({ |
77 | 134 | 'date': date, |
135 | 'offset': stop.departure_time, | |
18 | 136 | 'time': stop_time, |
137 | 'trip': trip, | |
138 | 'stop': stop, | |
127 | 139 | 'gone': gone, |
18 | 140 | }) |
17
fa3c822859b5
Refaktorioitu aikatauluhaku
Teemu Piippo <teemu@hecknology.net>
parents:
15
diff
changeset
|
141 | # Lajittele lopputulos saapumisajan mukaan. |
18 | 142 | result.sort(key = lambda schedule_entry: schedule_entry['time']) |
17
fa3c822859b5
Refaktorioitu aikatauluhaku
Teemu Piippo <teemu@hecknology.net>
parents:
15
diff
changeset
|
143 | return result |
90 | 144 | @property |
145 | def typename(self): | |
146 | if self.services == {'train'}: | |
147 | return 'train-station' | |
148 | elif self.services == {'tram'}: | |
149 | return 'tram-stop' | |
150 | elif self.services == {'ferry'}: | |
151 | return 'ferry-terminal' | |
152 | else: | |
153 | return 'bus-stop' | |
0 | 154 | |
24
e6bdb9c54096
Yhtenäistetty ohjelmakoodin kieli englanniksi
Teemu Piippo <teemu@hecknology.net>
parents:
23
diff
changeset
|
155 | class BusHalt: |
e6bdb9c54096
Yhtenäistetty ohjelmakoodin kieli englanniksi
Teemu Piippo <teemu@hecknology.net>
parents:
23
diff
changeset
|
156 | def __init__(self, arrival_time, departure_time, stop, trip, traveled_distance): |
e6bdb9c54096
Yhtenäistetty ohjelmakoodin kieli englanniksi
Teemu Piippo <teemu@hecknology.net>
parents:
23
diff
changeset
|
157 | self.arrival_time, self.departure_time, self.stop, self.trip = arrival_time, departure_time, \ |
e6bdb9c54096
Yhtenäistetty ohjelmakoodin kieli englanniksi
Teemu Piippo <teemu@hecknology.net>
parents:
23
diff
changeset
|
158 | stop, trip |
e6bdb9c54096
Yhtenäistetty ohjelmakoodin kieli englanniksi
Teemu Piippo <teemu@hecknology.net>
parents:
23
diff
changeset
|
159 | self.traveled_distance = traveled_distance |
127 | 160 | self.uuid = uuid.uuid4() |
23 | 161 | @property |
29 | 162 | def is_arrival(self): |
71
d2e19670b772
Remove assumptions and added some api stuff
Teemu Piippo <teemu@hecknology.net>
parents:
42
diff
changeset
|
163 | if profile['regions']['use-regions']: |
d2e19670b772
Remove assumptions and added some api stuff
Teemu Piippo <teemu@hecknology.net>
parents:
42
diff
changeset
|
164 | if not hasattr(self, 'cachedIsArrival'): |
d2e19670b772
Remove assumptions and added some api stuff
Teemu Piippo <teemu@hecknology.net>
parents:
42
diff
changeset
|
165 | if self.stop.region: |
d2e19670b772
Remove assumptions and added some api stuff
Teemu Piippo <teemu@hecknology.net>
parents:
42
diff
changeset
|
166 | iterator = iter(self.trip.schedule) |
29 | 167 | stop = next(iterator) |
71
d2e19670b772
Remove assumptions and added some api stuff
Teemu Piippo <teemu@hecknology.net>
parents:
42
diff
changeset
|
168 | while stop is not self: |
d2e19670b772
Remove assumptions and added some api stuff
Teemu Piippo <teemu@hecknology.net>
parents:
42
diff
changeset
|
169 | stop = next(iterator) |
d2e19670b772
Remove assumptions and added some api stuff
Teemu Piippo <teemu@hecknology.net>
parents:
42
diff
changeset
|
170 | for stop in iterator: |
d2e19670b772
Remove assumptions and added some api stuff
Teemu Piippo <teemu@hecknology.net>
parents:
42
diff
changeset
|
171 | if stop.stop.region != self.stop.region: |
d2e19670b772
Remove assumptions and added some api stuff
Teemu Piippo <teemu@hecknology.net>
parents:
42
diff
changeset
|
172 | self.cachedIsArrival = False |
d2e19670b772
Remove assumptions and added some api stuff
Teemu Piippo <teemu@hecknology.net>
parents:
42
diff
changeset
|
173 | break |
d2e19670b772
Remove assumptions and added some api stuff
Teemu Piippo <teemu@hecknology.net>
parents:
42
diff
changeset
|
174 | else: |
d2e19670b772
Remove assumptions and added some api stuff
Teemu Piippo <teemu@hecknology.net>
parents:
42
diff
changeset
|
175 | self.cachedIsArrival = True |
29 | 176 | else: |
71
d2e19670b772
Remove assumptions and added some api stuff
Teemu Piippo <teemu@hecknology.net>
parents:
42
diff
changeset
|
177 | self.cachedIsArrival = False |
d2e19670b772
Remove assumptions and added some api stuff
Teemu Piippo <teemu@hecknology.net>
parents:
42
diff
changeset
|
178 | return self.cachedIsArrival |
d2e19670b772
Remove assumptions and added some api stuff
Teemu Piippo <teemu@hecknology.net>
parents:
42
diff
changeset
|
179 | else: |
d2e19670b772
Remove assumptions and added some api stuff
Teemu Piippo <teemu@hecknology.net>
parents:
42
diff
changeset
|
180 | return self == self.trip.schedule[-1] |
94
e27c18f080d1
added an interesting trip portal
Teemu Piippo <teemu@hecknology.net>
parents:
93
diff
changeset
|
181 | def departure_datetime(self, date): |
e27c18f080d1
added an interesting trip portal
Teemu Piippo <teemu@hecknology.net>
parents:
93
diff
changeset
|
182 | import datetime |
e27c18f080d1
added an interesting trip portal
Teemu Piippo <teemu@hecknology.net>
parents:
93
diff
changeset
|
183 | return datetime.datetime.combine(date, datetime.time()) + self.departure_time |
e27c18f080d1
added an interesting trip portal
Teemu Piippo <teemu@hecknology.net>
parents:
93
diff
changeset
|
184 | def arrival_datetime(self, date): |
e27c18f080d1
added an interesting trip portal
Teemu Piippo <teemu@hecknology.net>
parents:
93
diff
changeset
|
185 | import datetime |
e27c18f080d1
added an interesting trip portal
Teemu Piippo <teemu@hecknology.net>
parents:
93
diff
changeset
|
186 | return datetime.datetime.combine(date, datetime.time()) + self.arrival_time |
0 | 187 | def __repr__(self): |
24
e6bdb9c54096
Yhtenäistetty ohjelmakoodin kieli englanniksi
Teemu Piippo <teemu@hecknology.net>
parents:
23
diff
changeset
|
188 | return 'BusHalt(%r, %r, %r, %r)' % (self.arrival_time, self.departure_time, self.stop, self.trip) |
71
d2e19670b772
Remove assumptions and added some api stuff
Teemu Piippo <teemu@hecknology.net>
parents:
42
diff
changeset
|
189 | def sign(self, long = False): |
d2e19670b772
Remove assumptions and added some api stuff
Teemu Piippo <teemu@hecknology.net>
parents:
42
diff
changeset
|
190 | from busroute import reduce_schedule |
d2e19670b772
Remove assumptions and added some api stuff
Teemu Piippo <teemu@hecknology.net>
parents:
42
diff
changeset
|
191 | return reduce_schedule( |
d2e19670b772
Remove assumptions and added some api stuff
Teemu Piippo <teemu@hecknology.net>
parents:
42
diff
changeset
|
192 | route = self.trip.concise_schedule(self), |
d2e19670b772
Remove assumptions and added some api stuff
Teemu Piippo <teemu@hecknology.net>
parents:
42
diff
changeset
|
193 | trip_length = self.trip.length - self.traveled_distance, |
d2e19670b772
Remove assumptions and added some api stuff
Teemu Piippo <teemu@hecknology.net>
parents:
42
diff
changeset
|
194 | long = long, |
d2e19670b772
Remove assumptions and added some api stuff
Teemu Piippo <teemu@hecknology.net>
parents:
42
diff
changeset
|
195 | ) |
0 | 196 | |
109 | 197 | class BusStopCluster: |
198 | def __init__(self): | |
199 | self.stops = set() | |
200 | self.cached_center = None | |
201 | self.name = None | |
202 | @property | |
203 | def url_name(self): | |
204 | return self.name.lower().replace('(', '').replace(')', '').replace(' ', '-') | |
205 | def add_stop(self, stop): | |
206 | assert not stop.cluster | |
207 | stop.cluster = self | |
208 | self.stops.add(stop) | |
209 | self.cached_center = None | |
210 | @property | |
211 | def center(self): | |
212 | if not self.cached_center: | |
213 | if self.stops: | |
214 | from statistics import median | |
215 | pointtype = type(next(iter(self.stops)).location) | |
216 | self.cached_center = pointtype( | |
217 | median(stop.location.x for stop in self.stops), | |
218 | median(stop.location.y for stop in self.stops), | |
219 | ) | |
220 | else: | |
221 | raise ValueError('an empty cluster has no center point') | |
222 | return self.cached_center | |
223 | def merge(self, other): | |
224 | for bus_stop in other.stops: | |
225 | bus_stop.cluster = self | |
226 | self.stops |= other.stops | |
227 | other.stops = set() | |
228 | other.cached_center = None | |
229 | def schedule(self, *, max_amount = 50): | |
230 | result = [] | |
231 | for stop in self.stops: | |
232 | result += stop.schedule(max_amount = max_amount) | |
233 | result.sort(key = lambda schedule_entry: schedule_entry['time']) | |
234 | return result[:max_amount] | |
114 | 235 | def __lt__(self, other): |
236 | return (self.name and other.name) and (self.name < other.name) or (id(self) < id(other)) | |
109 | 237 | |
238 | class CustomBusStopCluster(BusStopCluster): | |
239 | def __init__(self, *, name, stops): | |
240 | super().__init__() | |
241 | self.name = name | |
242 | self.stops = stops | |
243 | def add_stop(self, stop): | |
244 | return NotImplemented | |
245 | @property | |
246 | def url_name(self): | |
247 | from urllib.request import quote | |
248 | return 'custom?stops=' + ';'.join(stop.code for stop in self.stops) + '&name=' + quote(self.name) | |
249 | ||
114 | 250 | from collections import defaultdict |
24
e6bdb9c54096
Yhtenäistetty ohjelmakoodin kieli englanniksi
Teemu Piippo <teemu@hecknology.net>
parents:
23
diff
changeset
|
251 | routes = {} |
e6bdb9c54096
Yhtenäistetty ohjelmakoodin kieli englanniksi
Teemu Piippo <teemu@hecknology.net>
parents:
23
diff
changeset
|
252 | routes_per_id = {} |
e6bdb9c54096
Yhtenäistetty ohjelmakoodin kieli englanniksi
Teemu Piippo <teemu@hecknology.net>
parents:
23
diff
changeset
|
253 | all_trips = {} |
e6bdb9c54096
Yhtenäistetty ohjelmakoodin kieli englanniksi
Teemu Piippo <teemu@hecknology.net>
parents:
23
diff
changeset
|
254 | services = {} |
e6bdb9c54096
Yhtenäistetty ohjelmakoodin kieli englanniksi
Teemu Piippo <teemu@hecknology.net>
parents:
23
diff
changeset
|
255 | bus_stops = {} |
15
a22cdf28930f
Lisätty bussipysäkkien ryhmittely
Teemu Piippo <teemu@hecknology.net>
parents:
7
diff
changeset
|
256 | all_clusters = set() |
30 | 257 | viimeinen_käyttöpäivä = None |
258 | clusters_by_name = {} | |
24
e6bdb9c54096
Yhtenäistetty ohjelmakoodin kieli englanniksi
Teemu Piippo <teemu@hecknology.net>
parents:
23
diff
changeset
|
259 | services_for_day = {} |
114 | 260 | shapes = defaultdict(list) |
0 | 261 | |
93 | 262 | def load_buses(gtfs_zip_path): |
30 | 263 | global viimeinen_käyttöpäivä |
264 | from zipfile import ZipFile | |
265 | with ZipFile(gtfs_zip_path) as gtfs_zip: | |
88
3b86597c5a88
major update, moved the map to an osm patch
Teemu Piippo <teemu@hecknology.net>
parents:
81
diff
changeset
|
266 | print('Loading routes... ', file = stderr, end = '', flush = True) |
30 | 267 | with gtfs_zip.open('routes.txt') as file: |
268 | for row in read_csv(map(bytes.decode, file)): | |
269 | route = BusRoute(row) | |
270 | routes[route.reference] = route | |
271 | routes_per_id[route.id] = route | |
88
3b86597c5a88
major update, moved the map to an osm patch
Teemu Piippo <teemu@hecknology.net>
parents:
81
diff
changeset
|
272 | print('%d routes' % len(routes), file = stderr) |
93 | 273 | # Add services |
274 | import re | |
275 | service_patterns = {} | |
276 | if 'service-patterns' in profile: | |
277 | for service_type, regexps in profile['service-patterns'].items(): | |
278 | service_patterns[service_type] = {re.compile(regexp) for regexp in regexps.split('@')} | |
279 | if 'services' in profile and profile['services'].get('default-service'): | |
280 | print('Tagging services...', end = '') | |
281 | for route in routes.values(): | |
282 | for service_type, regexps in service_patterns.items(): | |
283 | if any(regexp.match(route.reference) for regexp in regexps): | |
284 | route.service = service_type | |
285 | break | |
286 | else: | |
287 | route.service = profile['services']['default-service'] | |
288 | print('') | |
88
3b86597c5a88
major update, moved the map to an osm patch
Teemu Piippo <teemu@hecknology.net>
parents:
81
diff
changeset
|
289 | print('Loading trips... ', file = stderr, end = '', flush = True) |
30 | 290 | shape_distances = {} |
71
d2e19670b772
Remove assumptions and added some api stuff
Teemu Piippo <teemu@hecknology.net>
parents:
42
diff
changeset
|
291 | try: |
d2e19670b772
Remove assumptions and added some api stuff
Teemu Piippo <teemu@hecknology.net>
parents:
42
diff
changeset
|
292 | with gtfs_zip.open('shapes.txt') as file: |
d2e19670b772
Remove assumptions and added some api stuff
Teemu Piippo <teemu@hecknology.net>
parents:
42
diff
changeset
|
293 | for row in read_csv(map(bytes.decode, file)): |
114 | 294 | list.append(shapes[row['shape_id']], (row['shape_pt_lat'], row['shape_pt_lon'])) |
71
d2e19670b772
Remove assumptions and added some api stuff
Teemu Piippo <teemu@hecknology.net>
parents:
42
diff
changeset
|
295 | shape_distances[row['shape_id']] = max(shape_distances.get(row['shape_id'], 0), float(row['shape_dist_traveled'])) |
d2e19670b772
Remove assumptions and added some api stuff
Teemu Piippo <teemu@hecknology.net>
parents:
42
diff
changeset
|
296 | except KeyError: |
d2e19670b772
Remove assumptions and added some api stuff
Teemu Piippo <teemu@hecknology.net>
parents:
42
diff
changeset
|
297 | pass |
29 | 298 | |
30 | 299 | with gtfs_zip.open('trips.txt') as file: |
300 | for row in read_csv(map(bytes.decode, file)): | |
301 | if row['service_id'] not in services: | |
302 | services[row['service_id']] = BusService(row['service_id']) | |
303 | route = routes_per_id[row['route_id']] | |
304 | trip = BusTrip( | |
305 | reference = row['trip_id'], | |
306 | route = route, | |
307 | service = services[row['service_id']], | |
71
d2e19670b772
Remove assumptions and added some api stuff
Teemu Piippo <teemu@hecknology.net>
parents:
42
diff
changeset
|
308 | length = shape_distances.get(row.get('shape_id'), 1) * float(profile['metrics']['shape-modifier']), |
90 | 309 | block_id = row.get('block_id') or row['service_id'], |
114 | 310 | shape = row.get('shape_id') |
30 | 311 | ) |
312 | route.trips.add(trip) | |
71
d2e19670b772
Remove assumptions and added some api stuff
Teemu Piippo <teemu@hecknology.net>
parents:
42
diff
changeset
|
313 | if trip.name in all_trips: |
d2e19670b772
Remove assumptions and added some api stuff
Teemu Piippo <teemu@hecknology.net>
parents:
42
diff
changeset
|
314 | print('Trip %s already exists' % trip.name) |
d2e19670b772
Remove assumptions and added some api stuff
Teemu Piippo <teemu@hecknology.net>
parents:
42
diff
changeset
|
315 | else: |
d2e19670b772
Remove assumptions and added some api stuff
Teemu Piippo <teemu@hecknology.net>
parents:
42
diff
changeset
|
316 | all_trips[trip.name] = trip |
88
3b86597c5a88
major update, moved the map to an osm patch
Teemu Piippo <teemu@hecknology.net>
parents:
81
diff
changeset
|
317 | print('%d trips' % len(all_trips), file = stderr) |
0 | 318 | |
30 | 319 | def read_date(teksti): |
320 | return date(int(teksti[:4]), int(teksti[4:6]), int(teksti[6:])) | |
321 | ||
322 | def read_time(teksti): | |
88
3b86597c5a88
major update, moved the map to an osm patch
Teemu Piippo <teemu@hecknology.net>
parents:
81
diff
changeset
|
323 | hour, minute, second = map(int, teksti.split(':')) |
3b86597c5a88
major update, moved the map to an osm patch
Teemu Piippo <teemu@hecknology.net>
parents:
81
diff
changeset
|
324 | return timedelta(hours = hour, minutes = minute, seconds = second) |
30 | 325 | |
93 | 326 | print('Loading dates... ', file = stderr, flush = True) |
30 | 327 | viimeinen_käyttöpäivä = date.today() |
29 | 328 | |
30 | 329 | def date_range(start_date, end_date, *, include_end = False): |
330 | ''' Generates date from start_date to end_date. If include_end is True, then end_date will be yielded. ''' | |
331 | current_date = start_date | |
332 | while current_date < end_date: | |
333 | yield current_date | |
334 | current_date += timedelta(1) | |
335 | if include_end: | |
336 | yield end_date | |
29 | 337 | |
30 | 338 | def add_day_to_service(service_name, day): |
339 | try: | |
340 | service = services[service_name] | |
341 | except KeyError: | |
342 | return | |
343 | else: | |
344 | service.dates.add(day) | |
345 | if day not in services_for_day: | |
346 | services_for_day[day] = set() | |
347 | services_for_day[day].add(service) | |
348 | global viimeinen_käyttöpäivä | |
349 | viimeinen_käyttöpäivä = max(day, viimeinen_käyttöpäivä) | |
29 | 350 | |
30 | 351 | def filter_day(row, day): |
352 | day_names = ['monday', 'tuesday', 'wednesday', 'thursday', 'friday', 'saturday', 'sunday'] | |
353 | return int(row[day_names[day.isoweekday() - 1]]) | |
0 | 354 | |
30 | 355 | with gtfs_zip.open('calendar.txt') as file: |
356 | for row in read_csv(map(bytes.decode, file)): | |
357 | for day in date_range(read_date(row['start_date']), read_date(row['end_date']), include_end = True): | |
358 | if filter_day(row, day): | |
359 | add_day_to_service(service_name = row['service_id'], day = day) | |
360 | ||
361 | with gtfs_zip.open('calendar_dates.txt') as file: | |
362 | for row in read_csv(map(bytes.decode, file)): | |
363 | add_day_to_service(service_name = row['service_id'], day = read_date(row['date'])) | |
364 | ||
365 | def services_available_at(day): | |
366 | for service in services.values(): | |
367 | if day in service.dates: | |
368 | yield service | |
369 | ||
88
3b86597c5a88
major update, moved the map to an osm patch
Teemu Piippo <teemu@hecknology.net>
parents:
81
diff
changeset
|
370 | print('Loading stops... ', file = stderr, end = '', flush = True) |
30 | 371 | with gtfs_zip.open('stops.txt') as file: |
372 | for row in read_csv(map(bytes.decode, file)): | |
88
3b86597c5a88
major update, moved the map to an osm patch
Teemu Piippo <teemu@hecknology.net>
parents:
81
diff
changeset
|
373 | location = Location(float(row['stop_lat']), float(row['stop_lon'])) |
30 | 374 | stop = BusStop( |
375 | reference = row['stop_id'], | |
376 | name = row['stop_name'], | |
377 | location = location, | |
71
d2e19670b772
Remove assumptions and added some api stuff
Teemu Piippo <teemu@hecknology.net>
parents:
42
diff
changeset
|
378 | code = row.get('stop_code', row['stop_id']), |
30 | 379 | ) |
380 | bus_stops[stop.reference] = stop | |
71
d2e19670b772
Remove assumptions and added some api stuff
Teemu Piippo <teemu@hecknology.net>
parents:
42
diff
changeset
|
381 | if profile['regions']['use-regions']: |
d2e19670b772
Remove assumptions and added some api stuff
Teemu Piippo <teemu@hecknology.net>
parents:
42
diff
changeset
|
382 | with open('regions-per-stop.json') as file: |
d2e19670b772
Remove assumptions and added some api stuff
Teemu Piippo <teemu@hecknology.net>
parents:
42
diff
changeset
|
383 | for stop_reference, region in json.load(file).items(): |
d2e19670b772
Remove assumptions and added some api stuff
Teemu Piippo <teemu@hecknology.net>
parents:
42
diff
changeset
|
384 | try: |
d2e19670b772
Remove assumptions and added some api stuff
Teemu Piippo <teemu@hecknology.net>
parents:
42
diff
changeset
|
385 | bus_stops[stop_reference].region = region |
d2e19670b772
Remove assumptions and added some api stuff
Teemu Piippo <teemu@hecknology.net>
parents:
42
diff
changeset
|
386 | except KeyError: |
d2e19670b772
Remove assumptions and added some api stuff
Teemu Piippo <teemu@hecknology.net>
parents:
42
diff
changeset
|
387 | pass |
81 | 388 | for bus_stop in bus_stops.values(): |
389 | if not hasattr(bus_stop, 'region'): | |
390 | bus_stop.region = None | |
88
3b86597c5a88
major update, moved the map to an osm patch
Teemu Piippo <teemu@hecknology.net>
parents:
81
diff
changeset
|
391 | print('%d stops' % len(bus_stops), file = stderr) |
21 | 392 | |
30 | 393 | from collections import defaultdict |
394 | bus_stops_by_name = defaultdict(set) | |
395 | for bus_stop in bus_stops.values(): | |
396 | bus_stops_by_name[bus_stop.name].add(bus_stop) | |
397 | bus_stops_by_name = dict(bus_stops_by_name) | |
15
a22cdf28930f
Lisätty bussipysäkkien ryhmittely
Teemu Piippo <teemu@hecknology.net>
parents:
7
diff
changeset
|
398 | |
30 | 399 | # ryhmittele bus_stops nimen mukaan |
41 | 400 | global all_clusters |
30 | 401 | all_clusters = [] |
402 | def cluster_bus_stops(): | |
403 | sorted_bus_stops = sorted(bus_stops.values(), key = lambda bus_stop: bus_stop.name) | |
404 | for bus_stop in sorted_bus_stops: | |
405 | if not bus_stop.cluster: | |
406 | stops_to_cluster = {bus_stop} | |
407 | # etsi pysäkin samannimiset vastaparit | |
408 | for pair_candidate in bus_stops_by_name[bus_stop.name]: | |
88
3b86597c5a88
major update, moved the map to an osm patch
Teemu Piippo <teemu@hecknology.net>
parents:
81
diff
changeset
|
409 | distance = pair_candidate.location.distance(bus_stop.location) |
30 | 410 | if pair_candidate is not bus_stop and distance <= 0.4: |
411 | stops_to_cluster.add(pair_candidate) | |
412 | for stop_to_cluster in stops_to_cluster: | |
413 | if stop_to_cluster.cluster: | |
414 | cluster = stop_to_cluster.cluster | |
415 | break | |
416 | else: | |
417 | cluster = BusStopCluster() | |
418 | all_clusters.append(cluster) | |
419 | for stop_to_cluster in stops_to_cluster: | |
420 | if not stop_to_cluster.cluster: | |
421 | cluster.add_stop(stop_to_cluster) | |
422 | # Merkitse muistiin pysäkkien vastaparit käyttäen hyväksi tämänhetkistä ryhmittelytietoa | |
423 | for bus_stop in bus_stops.values(): | |
424 | if bus_stop.cluster: | |
425 | bus_stop.pairs = bus_stop.cluster.stops - {bus_stop} | |
426 | # Ryhmitä ne bus_stops, joilla ei ollut omaa vastaparia, muiden pysäkkien kanssa | |
427 | for bus_stop in sorted_bus_stops: | |
428 | if len(bus_stop.cluster.stops) == 1: | |
429 | possibilities = set() | |
430 | for cluster in all_clusters: | |
431 | if cluster is not bus_stop.cluster: | |
88
3b86597c5a88
major update, moved the map to an osm patch
Teemu Piippo <teemu@hecknology.net>
parents:
81
diff
changeset
|
432 | distance = cluster.center.distance(bus_stop.location) |
30 | 433 | if distance <= 0.4: |
434 | possibilities.add((distance, cluster)) | |
435 | if possibilities: | |
436 | best = min(possibilities)[1] | |
437 | all_clusters.remove(bus_stop.cluster) | |
438 | best.merge(bus_stop.cluster) | |
15
a22cdf28930f
Lisätty bussipysäkkien ryhmittely
Teemu Piippo <teemu@hecknology.net>
parents:
7
diff
changeset
|
439 | |
30 | 440 | def shared_elements_in_n_sets(sets): |
441 | from itertools import combinations | |
442 | result = set() | |
443 | for pair in combinations(sets, 2): | |
444 | result |= pair[0] & pair[1] | |
445 | return result | |
15
a22cdf28930f
Lisätty bussipysäkkien ryhmittely
Teemu Piippo <teemu@hecknology.net>
parents:
7
diff
changeset
|
446 | |
30 | 447 | def name_clusters(): |
448 | from collections import defaultdict | |
449 | clusters_per_name = defaultdict(set) | |
450 | for cluster in all_clusters: | |
451 | name_representing_stop = min((len(stop.reference), stop.reference, stop) for stop in cluster.stops)[2] | |
452 | clusters_per_name[name_representing_stop.name].add(cluster) | |
453 | for name, clusters in clusters_per_name.items(): | |
454 | if len(clusters) == 1: | |
88
3b86597c5a88
major update, moved the map to an osm patch
Teemu Piippo <teemu@hecknology.net>
parents:
81
diff
changeset
|
455 | # Simple case: this cluster is the only one that wants this name. |
30 | 456 | next(iter(clusters)).name = name |
457 | else: | |
71
d2e19670b772
Remove assumptions and added some api stuff
Teemu Piippo <teemu@hecknology.net>
parents:
42
diff
changeset
|
458 | if profile['regions']['use-regions']: |
88
3b86597c5a88
major update, moved the map to an osm patch
Teemu Piippo <teemu@hecknology.net>
parents:
81
diff
changeset
|
459 | # Find out if all clusters are in different areas |
71
d2e19670b772
Remove assumptions and added some api stuff
Teemu Piippo <teemu@hecknology.net>
parents:
42
diff
changeset
|
460 | common_regions = shared_elements_in_n_sets({stop.region for stop in cluster.stops} for cluster in clusters) |
88
3b86597c5a88
major update, moved the map to an osm patch
Teemu Piippo <teemu@hecknology.net>
parents:
81
diff
changeset
|
461 | # Proposal: cluster -> the areas unique to the cluster |
71
d2e19670b772
Remove assumptions and added some api stuff
Teemu Piippo <teemu@hecknology.net>
parents:
42
diff
changeset
|
462 | proposal = { |
d2e19670b772
Remove assumptions and added some api stuff
Teemu Piippo <teemu@hecknology.net>
parents:
42
diff
changeset
|
463 | cluster: {stop.region for stop in cluster.stops} - common_regions - {None} |
d2e19670b772
Remove assumptions and added some api stuff
Teemu Piippo <teemu@hecknology.net>
parents:
42
diff
changeset
|
464 | for cluster in clusters |
d2e19670b772
Remove assumptions and added some api stuff
Teemu Piippo <teemu@hecknology.net>
parents:
42
diff
changeset
|
465 | } |
88
3b86597c5a88
major update, moved the map to an osm patch
Teemu Piippo <teemu@hecknology.net>
parents:
81
diff
changeset
|
466 | # If at most one cluster is without its own unique region, name the others by region and this one without any. |
71
d2e19670b772
Remove assumptions and added some api stuff
Teemu Piippo <teemu@hecknology.net>
parents:
42
diff
changeset
|
467 | if sum([1 for unique_areas in proposal.values() if not unique_areas]) <= 1: |
d2e19670b772
Remove assumptions and added some api stuff
Teemu Piippo <teemu@hecknology.net>
parents:
42
diff
changeset
|
468 | for cluster, unique_areas in proposal.items(): |
d2e19670b772
Remove assumptions and added some api stuff
Teemu Piippo <teemu@hecknology.net>
parents:
42
diff
changeset
|
469 | individual_cluster_name = name |
d2e19670b772
Remove assumptions and added some api stuff
Teemu Piippo <teemu@hecknology.net>
parents:
42
diff
changeset
|
470 | if unique_areas: |
d2e19670b772
Remove assumptions and added some api stuff
Teemu Piippo <teemu@hecknology.net>
parents:
42
diff
changeset
|
471 | individual_cluster_name += ' (' + min(unique_areas) + ')' |
d2e19670b772
Remove assumptions and added some api stuff
Teemu Piippo <teemu@hecknology.net>
parents:
42
diff
changeset
|
472 | cluster.name = individual_cluster_name |
d2e19670b772
Remove assumptions and added some api stuff
Teemu Piippo <teemu@hecknology.net>
parents:
42
diff
changeset
|
473 | break |
88
3b86597c5a88
major update, moved the map to an osm patch
Teemu Piippo <teemu@hecknology.net>
parents:
81
diff
changeset
|
474 | # If all else fails, just number them. |
71
d2e19670b772
Remove assumptions and added some api stuff
Teemu Piippo <teemu@hecknology.net>
parents:
42
diff
changeset
|
475 | for n, (_, cluster) in enumerate(sorted( |
d2e19670b772
Remove assumptions and added some api stuff
Teemu Piippo <teemu@hecknology.net>
parents:
42
diff
changeset
|
476 | min((stop.reference.lower(), cluster) for stop in cluster.stops) |
30 | 477 | for cluster in clusters |
71
d2e19670b772
Remove assumptions and added some api stuff
Teemu Piippo <teemu@hecknology.net>
parents:
42
diff
changeset
|
478 | ), 1): |
d2e19670b772
Remove assumptions and added some api stuff
Teemu Piippo <teemu@hecknology.net>
parents:
42
diff
changeset
|
479 | individual_cluster_name = name + '-' + str(n) |
d2e19670b772
Remove assumptions and added some api stuff
Teemu Piippo <teemu@hecknology.net>
parents:
42
diff
changeset
|
480 | cluster.name = individual_cluster_name |
30 | 481 | |
88
3b86597c5a88
major update, moved the map to an osm patch
Teemu Piippo <teemu@hecknology.net>
parents:
81
diff
changeset
|
482 | print('Clustering bus stops...') |
30 | 483 | cluster_bus_stops() |
484 | name_clusters() | |
485 | ||
486 | for cluster in all_clusters: | |
487 | if cluster.url_name in clusters_by_name: | |
488 | print('Warning: Clusters %r and %r share the same URL name: %r' % (cluster.name, clusters_by_name[cluster.url_name].name, cluster.url_name)) | |
15
a22cdf28930f
Lisätty bussipysäkkien ryhmittely
Teemu Piippo <teemu@hecknology.net>
parents:
7
diff
changeset
|
489 | else: |
30 | 490 | clusters_by_name[cluster.url_name] = cluster |
19
16fa9fb20b32
Lisätty pysäkkiryhmän aikataulunäkymä
Teemu Piippo <teemu@hecknology.net>
parents:
18
diff
changeset
|
491 | |
88
3b86597c5a88
major update, moved the map to an osm patch
Teemu Piippo <teemu@hecknology.net>
parents:
81
diff
changeset
|
492 | print('Loading schedules... ', end = '', flush = True, file = stderr) |
30 | 493 | with gtfs_zip.open('stop_times.txt') as file: |
494 | row_count = sum(line.count(b'\n') for line in file) | |
495 | with gtfs_zip.open('stop_times.txt') as file: | |
496 | progress = 0 | |
497 | for row in read_csv(map(bytes.decode, file)): | |
80 | 498 | if int(row.get('pickup_type', '') or '0') and int(row.get('drop_off_type', '') or '0'): |
71
d2e19670b772
Remove assumptions and added some api stuff
Teemu Piippo <teemu@hecknology.net>
parents:
42
diff
changeset
|
499 | continue |
30 | 500 | trip = all_trips[transform_trip_reference(row['trip_id'])] |
501 | arrival_time = read_time(row['arrival_time']) | |
502 | departure_time = read_time(row['departure_time']) | |
503 | stop = bus_stops[row['stop_id']] | |
71
d2e19670b772
Remove assumptions and added some api stuff
Teemu Piippo <teemu@hecknology.net>
parents:
42
diff
changeset
|
504 | traveled_distance = float(row.get('shape_dist_traveled', 1)) * float(profile['metrics']['shape-modifier']) |
30 | 505 | trip.schedule.append(BusHalt(arrival_time, departure_time, stop, trip, traveled_distance)) |
506 | stop.involved_trips.add(trip) | |
507 | progress += 1 | |
508 | if progress % 1000 == 0: | |
88
3b86597c5a88
major update, moved the map to an osm patch
Teemu Piippo <teemu@hecknology.net>
parents:
81
diff
changeset
|
509 | print('\rLoading schedules... %.1f%%' % (progress * 100 / row_count), end = ' ', file = stderr) |
3b86597c5a88
major update, moved the map to an osm patch
Teemu Piippo <teemu@hecknology.net>
parents:
81
diff
changeset
|
510 | print('\rLoading schedules... complete', file = stderr) |
30 | 511 | |
512 | for trip in all_trips.values(): | |
513 | from busroute import simplify_name | |
514 | schedule = trip.concise_schedule() | |
515 | try: | |
516 | trip.from_place = simplify_name(schedule[0]) | |
517 | trip.to_place = simplify_name(schedule[-1]) | |
518 | except IndexError: | |
519 | trip.from_place = '' | |
520 | trip.to_place = '' | |
28
670ffa424ded
Bussipysäkit tallentavat ajovuoronsa välimuistiin suoritusajan nopeuttamiseksi
Teemu Piippo <teemu@hecknology.net>
parents:
26
diff
changeset
|
521 | |
30 | 522 | for route in routes.values(): |
523 | from collections import Counter | |
524 | from busroute import simplify_name | |
525 | tally = Counter() | |
526 | for trip in route.trips: | |
527 | schedule = trip.concise_schedule() | |
528 | places = set(schedule) | |
529 | do_add = True | |
530 | assert type(schedule) is list | |
531 | for candidate in tally: | |
532 | if places.issubset(set(candidate)): | |
533 | do_add = False | |
534 | tally.update({tuple(candidate)}) | |
535 | if do_add: | |
536 | tally.update({tuple(schedule)}) | |
537 | try: | |
538 | most_common_route = tally.most_common(1)[0][0] | |
539 | route.description = simplify_name(most_common_route[0]) + ' - ' + simplify_name(most_common_route[-1]) | |
540 | except: | |
541 | route.description = '' | |
71
d2e19670b772
Remove assumptions and added some api stuff
Teemu Piippo <teemu@hecknology.net>
parents:
42
diff
changeset
|
542 | route.trips = sorted(route.trips, key = lambda trip: trip.schedule and trip.schedule[0].departure_time or timedelta()) |
28
670ffa424ded
Bussipysäkit tallentavat ajovuoronsa välimuistiin suoritusajan nopeuttamiseksi
Teemu Piippo <teemu@hecknology.net>
parents:
26
diff
changeset
|
543 | |
72 | 544 | if 'compatibility' in profile and profile['compatibility'].get('fix-destination-times', False): |
545 | # Fölin datassa on jotain tosi kummaa. Ilmeisesti ajovuoron viimeisen pysähdyksen saapumisaika on ihan täysin | |
546 | # väärin. Arvaan että se on seuraavan lähdön aika, mutta joka tapauksessa se on väärin. | |
547 | # Arvataan mikä se todellinen saapumisaika on. Se ei voi mennä kauhean paljon pahemmin vikaan kuin alkuperäinen | |
548 | # väärin oleva data. | |
549 | for trip in all_trips.values(): | |
550 | if len(trip.schedule) >= 2: | |
551 | bus_speed_coefficient = 750 # metriä minuutissa | |
552 | last_leg_distance = trip.schedule[-1].traveled_distance - trip.schedule[-2].traveled_distance | |
553 | trip.schedule[-1].arrival_time = trip.schedule[-2].departure_time + timedelta(minutes = last_leg_distance / bus_speed_coefficient) | |
71
d2e19670b772
Remove assumptions and added some api stuff
Teemu Piippo <teemu@hecknology.net>
parents:
42
diff
changeset
|
554 | |
d2e19670b772
Remove assumptions and added some api stuff
Teemu Piippo <teemu@hecknology.net>
parents:
42
diff
changeset
|
555 | global trips_by_vehicle_info |
d2e19670b772
Remove assumptions and added some api stuff
Teemu Piippo <teemu@hecknology.net>
parents:
42
diff
changeset
|
556 | trips_by_vehicle_info = {} |
d2e19670b772
Remove assumptions and added some api stuff
Teemu Piippo <teemu@hecknology.net>
parents:
42
diff
changeset
|
557 | for trip in all_trips.values(): |
d2e19670b772
Remove assumptions and added some api stuff
Teemu Piippo <teemu@hecknology.net>
parents:
42
diff
changeset
|
558 | trips_by_vehicle_info[(trip.block_id, trip.schedule[0].arrival_time)] = trip |
93 | 559 | # Add services to all bus stops |
560 | for route in routes.values(): | |
561 | for trip in route.trips: | |
562 | for halt in trip.schedule: | |
563 | halt.stop.services.add(route.service) | |
30 | 564 | |
565 | if __name__ == '__main__': | |
566 | profile.read('profiles/föli.ini') | |
71
d2e19670b772
Remove assumptions and added some api stuff
Teemu Piippo <teemu@hecknology.net>
parents:
42
diff
changeset
|
567 | load_buses('gtfs.zip') |
88
3b86597c5a88
major update, moved the map to an osm patch
Teemu Piippo <teemu@hecknology.net>
parents:
81
diff
changeset
|
568 | import busroute |
3b86597c5a88
major update, moved the map to an osm patch
Teemu Piippo <teemu@hecknology.net>
parents:
81
diff
changeset
|
569 | from regions import parse_regions |
3b86597c5a88
major update, moved the map to an osm patch
Teemu Piippo <teemu@hecknology.net>
parents:
81
diff
changeset
|
570 | busroute.regions = parse_regions('föli.osm') |