1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21 """
22 Handle merging CSV files into SABX files.
23 """
24
25 import csv
26 import sys
27
28 from sabx10.oxm import Point, Ride, Parking, Turn, Segment, Stop, Poi
29 from sabx10.templating import SabxProcessor
30
32 """
33 This is raised when the CsvProcessor._process_lat_lon function can't
34 interpret a point passed to it.
35 """
36 pass
37
39 """
40 Merge an SABX 1.0 file and a CSV file. Process it through an SABX 1.0
41 template and output it into a SABX 1.0 file.
42 """
43
44 - def __init__(self, template_file=None, man=None):
45 """
46 Adds the id, csv, and generate options to the standard SABX 1.0
47 template processor.
48
49 @param template_file: (optional) file name of template file
50 @type template_file: C{string}
51 @param man: (optional) extended program help
52 @type man: C{string}
53 """
54 SabxProcessor.__init__(self, template_file, man)
55
56 self.parser.usage = "%s csv_file" % self.parser.usage
57 self.parser.add_option("-d", "--id", dest="id",
58 help="id of segment to merge into",
59 default="1", metavar="ID")
60 self.parser.add_option("-b", "--blank", dest="blank",
61 action="store_true",
62 help="generate a blank CSV file",
63 default=False, metavar="BLANK")
64
66 csv = open(self.csv, "w")
67 csv.write("TYPE,START POINT,END POINT,TURN COMMENTS,TURN CUE,"
68 "ROAD,ROAD COMMENTS,LANES,SHOULDER,SPEED,TRAFFIC\n")
69 csv.close()
70
72 """
73 Get the CSV file name. It's expected to be the last command-line
74 argument. Print a blank CSV file and exit if asked to.
75 """
76 SabxProcessor.process_options(self, 1)
77 self.csv = self.args[-1]
78
79 if self.options.blank:
80 self._generate_blank()
81 sys.exit(0)
82
84 """
85 Get the lat, lon, and waypoint corresponding to the lat and lon values
86 passed in. If lat contains a point id, then the corresponding point is
87 found. Otherwise, the point closest to (lat, lon) is found.
88
89 @raises: L{BadPointError}
90
91 @param lat: latitude or point to search for
92 @type lat: C{string}
93 @param lon: longitude to search for
94 @type lon: C{string}
95 """
96 waypoint = None
97 if lat.find('.') == -1:
98 for pt in self.template_data['seg_dict'][self.options.id].waypoints:
99 if pt.id == lat:
100 waypoint = pt
101 lat = pt.lat
102 lon = pt.lon
103 break
104 else:
105 raise BadPointError(
106 "Matching point for '%s' not found!" % lat)
107 else:
108 dist = 100000.0
109 check_pt = Point(lat, lon)
110 for pt in self.template_data['seg_dict'][self.options.id].waypoints:
111 t_dist = check_pt.calculate_distance(pt)
112 if t_dist < dist:
113 waypoint = pt
114 dist = t_dist
115
116 return lat, lon, waypoint
117
119 """
120 Parse the CSV line as if it's a PARK item.
121
122 @raises: L{BadPointError}
123
124 @param id: id for this item
125 @type id: C{int}
126 @param item: CSV line item to parse
127 @type item: C{dict}
128 """
129 try:
130 lat, lon, wypt = self._process_lat_lon(item['START POINT'],
131 item['END POINT'])
132 except BadPointError as bpe:
133 raise BadPointError("Bad parking point: %s" % bpe)
134
135 return Parking(str(id), item['ROAD'], lat, lon)
136
138 """
139 Parse the CSV line as if it's a ROAD item, and remove the turn data
140 from it.
141
142 @param id: id for this item
143 @type id: C{int}
144 @param fromto: fromto part of the turn
145 @type fromto: C{string}
146 @param seg: CSV ROAD item to parse
147 @type seg: C{dict}
148 """
149 return Turn(str(id), "%s to %s" % (fromto, seg['ROAD']),
150 "%s %s" % (seg['TURN CUE'], seg['ROAD']),
151 seg['TURN COMMENTS'])
152
154 """
155 Get the waypoints for the corresponding segment. These are the points
156 from START POINT to END POINT.
157
158 @param seg: segment to get points for
159 @type seg: SABX 1.0 L{Segment}
160 """
161 seg_pts = []
162 in_pts = False
163 for pt in self.template_data['seg_dict'][self.options.id].waypoints:
164 if pt.id == seg['START POINT']:
165 in_pts = True
166
167 if in_pts:
168 seg_pts.append(pt)
169
170 if pt.id == seg['END POINT']:
171 in_pts = False
172
173 return seg_pts
174
176 """
177 Parse the CSV line as if it's a ROAD item, and remove the segment data
178 from it.
179
180 @param id: id for this item
181 @type id: C{int}
182 @param fromto: fromto part of the turn
183 @type fromto: C{string}
184 @param seg: CSV ROAD item to parse
185 @type seg: C{dict}
186 """
187 return Segment(str(id), seg['ROAD'], fromto, seg['ROAD COMMENTS'],
188 seg['LANES'], seg['SHOULDER'], seg['TRAFFIC'],
189 seg['SPEED'], self._get_segment_waypoints(seg))
190
192 """
193 Update the fromto field in a segment.
194
195 @param seg: segment to update
196 @type seg: SABX 1.0 L{Segment}
197 @param tofrom: value to update with
198 @type tofrom: C{string}
199 """
200 seg.fromto = "%s to %s" % (seg.fromto, tofrom)
201
203 """
204 Parse the CSV line as if it's a STOP item.
205
206 @raises: L{BadPointError}
207
208 @param id: id for this item
209 @type id: C{int}
210 @param item: CSV line item to parse
211 @type item: C{dict}
212 """
213 try:
214 lat, lon, wypt = self._process_lat_lon(item['START POINT'],
215 item['END POINT'])
216 except BadPointError as bpe:
217 raise BadPointError("Bad stop point: %s" % bpe)
218
219 if wypt.stop is None:
220 wypt.stop = str(id)
221 else:
222 wypt.stop = "%s,%s" % (wypt.stop, str(id))
223 return Stop(str(id), item['TURN CUE'], item['ROAD'], lat, lon)
224
226 """
227 Parse the CSV line as if it's a POI item.
228
229 @raises: L{BadPointError}
230
231 @param id: id for this item
232 @type id: C{int}
233 @param item: CSV line item to parse
234 @type item: C{dict}
235 """
236 try:
237 lat, lon, wypt = self._process_lat_lon(item['START POINT'],
238 item['END POINT'])
239 except BadPointError as bpe:
240 raise BadPointError("Bad poi point: %s" % bpe)
241
242 if wypt.poi is None:
243 wypt.poi = str(id)
244 else:
245 wypt.poi = "%s,%s" % (wypt.poi, str(id))
246 return Poi(str(id), item['ROAD'], lat, lon)
247
249 """
250 Parse the CSV file and merge it with the SABX 1.0 template data.
251 """
252 new_sabx = {}
253 new_sabx['park_list'] = []
254 new_sabx['park_dict'] = {}
255
256 new_sabx['turn_list'] = []
257 new_sabx['turn_dict'] = {}
258
259 new_sabx['seg_list'] = []
260 new_sabx['seg_dict'] = {}
261
262 new_sabx['stop_list'] = []
263 new_sabx['stop_dict'] = {}
264
265 new_sabx['poi_list'] = []
266 new_sabx['poi_dict'] = {}
267
268 new_ride = Ride('1', '', '', [], [])
269 new_sabx['ride_list'] = [new_ride]
270 new_sabx['ride_dict'] = {'1': new_ride}
271
272 fromto = "parking"
273 prev_seg = None
274
275
276
277 for index, row in enumerate(
278 csv.DictReader(open(self.csv)), start=1):
279
280
281 if row['TYPE'] == 'RIDE':
282 new_ride.description = row['ROAD']
283
284
285 if row['TYPE'] == 'PARK':
286 new_parking = self._parse_parking(index, row)
287 new_sabx['park_list'].append(new_parking)
288 new_sabx['park_dict'][new_parking.id] = new_parking
289 new_ride.parking = new_parking.id
290
291
292 elif row['TYPE'] == 'ROAD':
293 new_turn = self._parse_turn(index, fromto, row)
294 new_sabx['turn_list'].append(new_turn)
295 new_sabx['turn_dict'][new_turn.id] = new_turn
296 new_ride.turns.append(new_turn.id)
297
298 new_seg = self._parse_segment(index, fromto, row)
299 new_sabx['seg_list'].append(new_seg)
300 new_sabx['seg_dict'][new_seg.id] = new_seg
301 new_ride.segs.append(new_seg.id)
302
303 fromto = new_seg.road
304 if prev_seg:
305 self._update_segment_fromto(prev_seg, fromto)
306 prev_seg = new_seg
307
308
309 elif row['TYPE'] == 'STOP':
310 new_stop = self._parse_stop(index, row)
311 new_sabx['stop_list'].append(new_stop)
312 new_sabx['stop_dict'][new_stop.id] = new_stop
313
314
315 elif row['TYPE'] == 'POI':
316 new_poi = self._parse_poi(index, row)
317 new_sabx['poi_list'].append(new_poi)
318 new_sabx['poi_dict'][new_poi.id] = new_poi
319
320 return new_sabx
321
323 """
324 Update the template data by merging it with the specified CSV data.
325 """
326 SabxProcessor.get_template_data(self)
327 new_sabx = self._parse_csv()
328 self.template_data['park_list'], self.template_data['park_dict'] = \
329 new_sabx['park_list'], new_sabx['park_dict']
330 self.template_data['turn_list'], self.template_data['turn_dict'] = \
331 new_sabx['turn_list'], new_sabx['turn_dict']
332 self.template_data['seg_list'], self.template_data['seg_dict'] = \
333 new_sabx['seg_list'], new_sabx['seg_dict']
334 self.template_data['stop_list'], self.template_data['stop_dict'] = \
335 new_sabx['stop_list'], new_sabx['stop_dict']
336 self.template_data['poi_list'], self.template_data['poi_dict'] = \
337 new_sabx['poi_list'], new_sabx['poi_dict']
338 self.template_data['ride_list'], self.template_data['ride_dict'] = \
339 new_sabx['ride_list'], new_sabx['ride_dict']
340