1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22 """
23 Segment handling.
24 """
25 from geom import Point, Line, Box
26 from utils import get_from_id, check_version
27
28
29
30
31
33 """
34 A C{Waypoint} object sub-classes L{Point} and adds stop and POI references.
35
36 @ivar stop: space-delimited list of stop id's for this waypoint
37 @type stop: C{string}
38 @ivar poi: space-delimited list of poi id's for this waypoint
39 @type poi: C{string}
40 """
41 - def __init__(self, id, stop, poi, lat, lon, ele, usgs):
42 """
43 Save the passed-in data.
44
45 @param id: id of the C{Waypoint}
46 @type id: C{string}
47 @param stop: space-delimited list of stop id's for this waypoint
48 @type stop: C{string}
49 @param poi: space-delimited list of poi id's for this waypoint
50 @type poi: C{string}
51 @param lat: latitude of the waypoint
52 @type lat: C{float}
53 @param lon: longitude of the waypoint
54 @type lon: C{float}
55 @param ele: observed elevation for this waypoint (meters above
56 sea level)
57 @type ele: C{float}
58 @param usgs: USGS elevation for this waypoint (meters above sea level)
59 @type usgs: C{float}
60 """
61 Point.__init__(self, lat, lon, ele, usgs, id)
62 self.stop = stop
63 self.poi = poi
64
66 """
67 Create a new C{Waypoint} with the same data as this one.
68
69 @return: duplicate C{Waypoint}
70 @rtype: C{Waypoint}
71 """
72 return Waypoint(self.id, None, None,
73 self.lat, self.lon, self.ele, self.usgs)
74
76 """
77 A C{Segment} object sub-classes L{Line} and adds a host of extra data.
78
79 @ivar id: id of the C{Segment}
80 @type id: C{string}
81 @ivar road: name of road for this C{Segment}
82 @type road: C{string}
83 @ivar fromto: SEGMENT_X to SEGMENT_Y
84 @type fromto: C{string}
85 @ivar comments: Extra information about this C{Segment}
86 @type comments: C{string}
87 @ivar lanes: number of lanes
88 @type lanes: C{string}
89 @ivar shoulder: width of shoulder
90 @type shoulder: C{string}
91 @ivar traffic: amount of traffic
92 @type traffic: C{string}
93 @ivar speed: speed limit
94 @type speed: C{string}
95 """
96 - def __init__(self, id, road, fromto, comments,
97 lanes, shoulder, traffic, speed, waypoints):
98 """
99 Save the passed-in data.
100
101 @param id: id of the C{Segment}
102 @type id: C{string}
103 @param road: name of road for this C{Segment}
104 @type road: C{string}
105 @param fromto: SEGMENT_X to SEGMENT_Y
106 @type fromto: C{string}
107 @param comments: Extra information about this C{Segment}
108 @type comments: C{string}
109 @param lanes: number of lanes
110 @type lanes: C{string}
111 @param shoulder: width of shoulder
112 @type shoulder: C{string}
113 @param traffic: amount of traffic
114 @type traffic: C{string}
115 @param speed: speed limit
116 @type speed: C{string}
117 """
118 Line.__init__(self, waypoints)
119 self.id = id
120 self.road = road
121 self.fromto = fromto
122 self.comments = comments
123 self.lanes = lanes
124 self.shoulder = shoulder
125 self.traffic = traffic
126 self.speed = speed
127
129 """
130 Take the C{Element} for a waypoint and turn it into a L{Waypoint} object.
131
132 @param xml_point: C{Element} for a waypoint
133 @type xml_point: C{Element}
134
135 @return: L{Waypoint} object
136 @rtype: L{Waypoint}
137 """
138 stop = None
139 if 'stop' in xml_point.attrib:
140 stop = xml_point.attrib['stop']
141 poi = None
142 if 'poi' in xml_point.attrib:
143 poi = xml_point.attrib['poi']
144 return Waypoint(id = xml_point.attrib['id'],
145 stop = stop,
146 poi = poi,
147 lat = xml_point.findtext('lat'),
148 lon = xml_point.findtext('lon'),
149 ele = xml_point.findtext('ele'),
150 usgs = xml_point.findtext('usgs'))
151
153 """
154 Take the C{Element} for a segment and parse all the waypoints it contains.
155
156 @param xml_seg: C{Element} for a segment
157 @type xml_seg: C{Element}
158
159 @return: C{list} of L{Waypoint} objects
160 @rtype: C{list} of L{Waypoint}
161 """
162 return [_parse_waypoint(xml_pt)
163 for xml_pt in xml_seg.findall('waypoint')]
164
166 """
167 Take the C{Element} for a segment and turn it into a L{Segment} object.
168
169 @param xml_seg: C{Element} for a segment
170 @type xml_seg: C{Element}
171
172 @return: L{Segment} object
173 @rtype: L{Segment}
174 """
175 return Segment(id = xml_seg.attrib['id'],
176 road = xml_seg.findtext('road'),
177 fromto = xml_seg.findtext('fromto'),
178 comments = xml_seg.findtext('comments'),
179 lanes = xml_seg.findtext('lanes'),
180 shoulder = xml_seg.findtext('shoulder'),
181 traffic = xml_seg.findtext('traffic'),
182 speed = xml_seg.findtext('speed'),
183 waypoints = _parse_segment_waypoints(xml_seg))
184
186 """
187 Get all the segment elements in the given C{Element} tree and create a list
188 of them with L{Segment} objects.
189
190 @param xml_tree: root of C{Element} tree that has segments in it
191 @type xml_tree: C{Element} or C{ElementTree}
192
193 @return: segments in a list and a dictionary
194 @rtype: (C{list} of L{Segment},C{dict} of L{Segment})
195 """
196 xml_segs = xml_tree.findall('segment')
197 seg_list = []
198 seg_dict = {}
199 for xml_seg in xml_segs:
200 new_seg = _parse_segment_xml(xml_seg)
201 seg_list.append(new_seg)
202 seg_dict[new_seg.id] = new_seg
203
204 return seg_list, seg_dict
205
206
207
208
209
211 """
212 Process the ride, creating L{Segment} objects for each of its segment
213 references.
214
215 @param xml_ride: C{Element} for a ride
216 @type xml_ride: C{Element}
217 @param xml_segs: C{list} of C{Element} segment objects for this rideset
218 @type xml_segs: C{list} of C{Element}s
219
220 @return: C{list} of L{Segment} objects
221 @rtype: C{list} of L{Segment}
222 """
223 return [_parse_segment_xml(get_from_id(xml_segs, seg.attrib['id']))
224 for seg in xml_ride.findall('segment_ref')]
225
227 """
228 Apply an elevation correction to all the points in a list of waypoints.
229
230 @param points: list of points to correct
231 @type points: C{list} of L{Waypoint}
232 @param correction: ammount to add to the L{Waypoint} elevations
233 @type correction: C{float}
234
235 @return: C{None}
236 @rtype: C{None}
237 """
238 for pt in points:
239 pt.ele += correction
240
242 """
243 Process the ride segments, making sure that the rise/fall between segment
244 C{ele} endpoints is the same as the rise/fall of the USGS data. This helps
245 things out because C{ele} data taken from different rides can be off from
246 eachother, though the relative data for the ride is correct. This can make
247 for sudden jumps in the elevation between segments, which makes for funny
248 looking graphs and elevation analysis.
249
250 @param ride_segs: C{list} of L{Segment} objects for the ride
251 @type ride_segs: C{list} of L{Segment}
252
253 @return: C{None}
254 @rtype: C{None}
255 """
256 correction = 0.0
257 for index in range(len(ride_segs)-1):
258 usgs_rise = ride_segs[index+1].waypoints[0].usgs - \
259 ride_segs[index].waypoints[-1].usgs
260 ele_rise = ride_segs[index+1].waypoints[0].ele - \
261 ride_segs[index].waypoints[-1].ele
262 _correct_points(ride_segs[index].waypoints, correction)
263 correction += usgs_rise - ele_rise
264 _correct_points(ride_segs[-1].waypoints, correction)
265
267 """
268 Process the ride segments, connecting each to the successive segment by
269 making the final point of each segment be the same as the first point of
270 the following segment.
271
272 @param ride_segs: C{list} of L{Segment} objects for the ride
273 @type ride_segs: C{list} of L{Segment}
274
275 @return: C{None}
276 @rtype: C{None}
277 """
278 for index in range(len(ride_segs)-1):
279 ride_segs[index].waypoints.append(
280 ride_segs[index+1].waypoints[0].dup_point_data())
281
283 """
284 Process a L{Segment}, adding pertinent calculated data.
285
286 Calculated data includes:
287 - length: of segment
288 - distance: in ride of start of segment
289 - start_dist: same as distance
290 - end_dist: distance in ride of end of segment
291 - mid_index: index of middle L{Waypoint}
292 - lat: latitude of starting L{Waypoint}
293 - lon: longitude of starting L{Waypoint}
294 - mid_lat: latitude of middle L{Waypoint}
295 - mid_lon: longitude of middle L{Waypoint}
296 - index: index of segment in ride
297 - bounds: bounding box for all L{Waypoint}s in the box
298
299 @param seg: L{Segment} to process
300 @type seg: L{Segment}
301 @param index: index for this segment
302 @type index: C{int}
303 @param cum_distance: distance so far for this ride
304 @type cum_distance: C{float}
305
306 @return: C{None}
307 @rtype: C{None}
308 """
309 seg.length = seg.calc_length()
310 seg.distance = cum_distance
311 seg.start_dist = cum_distance
312 seg.end_dist = cum_distance + seg.length
313 seg.comments = " ".join(seg.comments.split())
314
315 mid_index = (len(seg.waypoints) - 1) / 2
316 seg.lat = seg.waypoints[0].lat
317 seg.lon = seg.waypoints[0].lon
318 seg.mid_lat = seg.waypoints[mid_index].lat
319 seg.mid_lon = seg.waypoints[mid_index].lon
320
321 seg.index = index
322
323 seg.bounds = Box()
324 for pt in seg.waypoints:
325 seg.bounds.expand_to_point(pt.lat, pt.lon)
326
328 """
329 Process the segment references for the given ride and generate a list of
330 L{Segment} objects for it and the bounding box for all of the segments.
331
332 @param xml_ride: C{Element} for a ride
333 @type xml_ride: C{Element}
334 @param xml_segs: C{list} of C{Element} segment objects for this rideset
335 @type xml_segs: C{list} of C{Element}s
336 @param correct_ele: make sure that the segment elevations match-up?
337 @type correct_ele: C{boolean}
338
339 @return: (C{list} of L{Segment},C{bounds})
340 @rtype: (C{list},L{Box})
341 """
342 """ Process the segments in the ride. """
343 cum_distance = 0.0
344 bounds = Box()
345
346 ride_segs = _get_ride_segs(xml_ride, xml_segs)
347 if correct_ele:
348 _correct_elevations(ride_segs)
349 _connect_segments_to_following_segment(ride_segs)
350 for index, seg in enumerate(ride_segs):
351 _process_segment(seg, index, cum_distance)
352 cum_distance += seg.length
353 bounds.expand_to_box(seg.bounds)
354
355 return ride_segs, bounds
356