1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22 """
23 Various constants and utility functions used by the SABX library.
24
25 @var cur_version: current version of the SABX file format (always "1.0" for
26 the SABX10 library)
27 @type cur_version: C{string}
28 @var rad_to_nm: multiply a radian value by this to convert it to nautical miles
29 @type rad_to_nm: C{float}
30 @var nm_to_rad: multiply a nautical mile value by this to convert it to radians
31 @type nm_to_rad: C{float}
32 @var nm_to_statute: multiply a nautical mile value by this to convert it to
33 statute miles
34 @type nm_to_statute: C{float}
35 @var statute_to_nm: multiply a statute mile value by this to convert it to
36 nautical miles
37 @type statute_to_nm: C{float}
38 @var meter_feet: number of feet in a meter
39 @type meter_feet: C{float}
40 @var mile_feet: number of feet in a mile
41 @type mile_feet: C{float}
42 """
43 from math import *
44 import xml.etree.ElementTree as et
45
46
47
48
49
50 rad_to_nm = 180 * 60 / pi
51 nm_to_rad = pi / (180 * 60)
52 nm_to_statute = 57875.0 / 50292.0
53 statute_to_nm = 50292.0 / 57875.0
54 meter_feet = 3.28083989501312
55 mile_feet = 5280.0
56 kilometer_miles = 0.621371192
57
59 '''
60 Calculate the distance between the two points (C{lat1},C{lon1}) and
61 (C{lat2},C{lon2}) in statute miles.
62
63 @param lat1: decimal degrees
64 @type lat1: C{float}
65 @param lon1: decimal degrees (west is negative)
66 @type lon1: C{float}
67 @param lat2: decimal degrees
68 @type lat2: C{float}
69 @param lon2: decimal degrees (west is negative)
70 @type lon2: C{float}
71
72 @return: distance in statute miles
73 @rtype: C{float}
74 '''
75 lat1 = radians(float(lat1))
76 lon1 = radians(float(lon1))
77 lat2 = radians(float(lat2))
78 lon2 = radians(float(lon2))
79 rad_dist = 2 * asin(
80 sqrt(
81 pow(sin((lat1-lat2)/2), 2) +
82 cos(lat1) * cos(lat2) *
83 pow(sin((lon1-lon2)/2),2)
84 )
85 )
86 nm_dist = rad_dist * rad_to_nm
87 return nm_dist * nm_to_statute
88
90 """
91 Calculate a point (C{lat},C{lon}) that is C{distance} statute miles
92 from the point (C{lat1},C{lon1}) along a course C{true_course} degrees.
93
94 Some useful C{true_course} values:
95 - 0.0 - north
96 - 90.0 - east
97 - 180.0 - south
98 - 270.0 - west
99
100 @param lat1: decimal degrees
101 @type lat1: C{float}
102 @param lon1: decimal degrees (west is negative)
103 @type lon1: C{float}
104 @param distance: distance from the point in statute miles
105 @type distance: C{float}
106 @param true_course: true course from the point in degrees
107 @type true_course: C{float}
108
109 @return: (C{lat},C{lon}) representing the calculated point
110 @rtype: (C{float},C{float})
111 """
112
113 distance = (distance * statute_to_nm) * nm_to_rad
114 true_course = (pi / 180) * true_course
115 lat1 = radians(lat1)
116 lon1 = radians(-lon1)
117
118 lat = asin( sin(lat1) * cos(distance) + cos(lat1) *
119 sin(distance) * cos(true_course) )
120 if cos(lat) == 0.0:
121 lon = lon1
122 else:
123 lon = (
124 (lon1 - asin( sin(true_course) * sin(distance) / cos(lat) ) + pi) %
125 (2*pi) ) - pi
126
127 return degrees(lat), degrees(-lon)
128
129
130
131
132
133 cur_version = "1.0"
134
136 """
137 This exception is raised to indicate an incorrect SABX file version was
138 encoutered.
139 """
140 pass
141
143 """
144 Check the version of the XML tree.
145
146 @param xml_tree: an C{ElementTree} C{Element} that's the root of an SABX
147 XML tree
148 @type xml_tree: C{Element}
149
150 @raise VersionException: when the given tree is not of the current version,
151 this exception is raised
152
153 @return: C{True} to indicate good version
154 @rtype: C{boolean}
155 """
156 if xml_tree.attrib['version'] != cur_version:
157 raise VersionException('Version %s of SABX format expected.' %
158 cur_version)
159 return True
160
161
162
163
164
166 """
167 Find an C{ElementTree} element with the given id in a list of elements.
168
169 I can't believe element tree doesn't provide something like this.
170 Actually, it looks like element tree 1.3 may provide something like this
171 with their XPath support - I need to check this out.
172
173 @param elements: C{list} of C{ElementTree} C{Element}s
174 @type elements: C{list}
175 @param id: id of element to find
176 @type id: C{string}
177
178 @return: C{Eement} found or C{None}
179 @rtype: C{Element}
180 """
181 for element in elements:
182 if element.attrib['id'] == id:
183 return element
184 return None
185
187 """
188 Read an XML file using C{ElementTree} tree, stripping default namespace
189 strings from all elements.
190
191 This routine is a little bit precarious. Its aim is to strip the default
192 namespace {uri} from tags so that you don't have to put all that text into
193 find, findall, findtext, etc... when searching the XML tree using the
194 C{ElementTree} stuff.
195
196 This should work most of the time. That is, when there is only one default
197 namespace declared, in the root of the XML tree, then it will be just fine.
198 In other instances, where the default namespace changes throughout the XML
199 document, the behavior can be unexpected.
200
201 Actually, the behavior of this function isn't unexpected. It will work
202 just fine. It's the behaviour of anything using it that will be
203 unexpected. If you change default namespaces, and you have tags that have
204 duplicate local portions that are differentiated by the namespace, then
205 they will all be retrieved by the find... calls. This may not be what you
206 want. Luckily, in the limited world that this routine operates in (so
207 far), this isn't a problem. GPX, TCX, and SABX files all have one default
208 namespace, declared in the root element. Let's hope.
209
210 @param source: XML file to read
211 @type source: C{string} or open file handle
212
213 @return: tree root C{Element} (B{NOT} an C{ElementTree} object)
214 @rtype: C{Element}
215 """
216 events = ("start", "end", "start-ns")
217 root = None
218 def_namespace = ""
219 for event, elem in et.iterparse(source, events=events):
220 if event == "start":
221 if root is None:
222 root = elem
223 elif event == "start-ns":
224 if elem[0] == '':
225 if elem[1]:
226 def_namespace = "{%s}" % elem[1]
227 else:
228 def_namespace = ""
229 else:
230 if def_namespace:
231 elem.tag = elem.tag.replace(def_namespace, "")
232 return root
233