1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22 """
23 All the geometric objects needed to represent an SABX file.
24 """
25 from utils import calculate_distance, pt_dist_from_pt, meter_feet
26
28 """
29 A C{Point} object is a (C{lat},C{lon}) pair that can optionally have
30 elevations and an id.
31
32 @ivar id: id of point
33 @type id: C{string}
34 @ivar lat: decimal degrees
35 @type lat: C{float}
36 @ivar lon: decimal degrees (west is negative)
37 @type lon: C{float}
38 @ivar usgs: USGS elevation for this point (meters above see level)
39 @type usgs: C{float}
40 @ivar ele: observed elevation for this point (meters above see level)
41 @type ele: C{float}
42 """
43
44 - def __init__(self, lat=0.0, lon=0.0, ele=None, usgs=None, id=None):
45 """
46 Save the passed-in data and make sure elevations are filled-in
47 properly.
48
49 This class is agnostic about what units C{ele} and C{usgs} are supplied
50 in, but SABX specifies them as meters.
51
52 @param id: id of point
53 @type id: C{string}
54 @param lat: degrees
55 @type lat: C{float}
56 @param lon: degrees (west is negative)
57 @type lon: C{float}
58 @param usgs: USGS elevation for this point (meters above see level)
59 @type usgs: C{float}
60 @param ele: observed elevation for this point (meters above see level)
61 @type ele: C{float}
62 """
63 self.id = id
64 if lat:
65 self.lat = float(lat)
66 else:
67 self.lat = 0.0
68 if lon:
69 self.lon = float(lon)
70 else:
71 self.lon = 0.0
72
73 self.usgs = None
74 self.ele = None
75 if usgs is not None:
76 self.usgs = float(usgs)
77 self.ele = self.usgs
78 if ele is not None:
79 self.ele = float(ele)
80
82 """
83 Calculate the distance from this point to the given point,
84 in statue miles.
85
86 @param point: point to calculate distance to
87 @type point: L{Point}
88
89 @return: distance in statute miles
90 @rtype: C{float}
91 """
92 if point is self:
93 return 0.0
94
95 return calculate_distance(self.lat, self.lon, point.lat, point.lon)
96
98 """
99 Calculate a point C{distance} statute miles from this point
100 along a course C{true_course} degrees
101
102 Some useful C{true_course} values:
103 - 0.0 - north
104 - 90.0 - east
105 - 180.0 - south
106 - 270.0 - west
107
108 @param distance: distance from this point in statute miles
109 @type distance: C{float}
110 @param true_course: true course from this point in degrees
111 @type true_course: C{float}
112
113 @return: Point object representing calculated point
114 @rtype: L{Point}
115 """
116 return pt_dist_from_pt(self.lat, self.lon, distance, true_course)
117
119 pt_from = pts[0]
120 for pt_to in pts[1:]:
121 yield pt_from, pt_to
122 pt_from = pt_to
123
125 """
126 A C{Line} object is an ordered set of L{Point} objects
127 representing a line.
128
129 @ivar waypoints: list of L{Point} objects
130 @type waypoints: C{list}
131 """
132
134 """
135 Save the passed-in data.
136
137 @param waypoints: list of L{Point} objects
138 @type waypoints: C{list}
139 """
140 self.waypoints = waypoints
141
143 """
144 Calculate the length of this C{line} in statue miles.
145
146 @return: length in statute miles
147 @rtype: C{float}
148 """
149 length = 0.0
150 for pt_from, pt_to in _pt_pairs(self.waypoints):
151 length += pt_from.calculate_distance(pt_to)
152 return length
153
155 """
156 Discover the lowest and highest elevations of this C{line}.
157
158 @return: (C{lowest},C{highest}) in feet
159 @rtype: (C{float},C{float})
160 """
161 highest = 0.0
162 lowest = 20000.0
163 for point in self.waypoints:
164 highest = max(highest, point.ele)
165 lowest = min(lowest, point.ele)
166 return lowest * meter_feet, highest * meter_feet
167
169 if (check > left and check < right) or \
170 (check > right and check < left):
171 return True
172 return False
173
175 """
176 A rectangle, represented by bottom left and top right corners.
177
178 @ivar min_lat: minimum latitude (bottom edge in northern hemisphere)
179 @type min_lat: C{float}
180 @ivar min_lon: minimum longitude (left edge in western hemisphere)
181 @type min_lon: C{float}
182 @ivar max_lat: maximum latitude (top edge in northern hemisphere)
183 @type max_lat: C{float}
184 @ivar max_lon: maximum longitude (right edge in western hemisphere)
185 @type max_lon: C{float}
186 """
187
188 - def __init__(self, min_lat=200.0, min_lon=200.0,
189 max_lat=-200.0, max_lon=-200.0):
190 """
191 Save the passed-in data.
192
193 @param min_lat: minimum latitude (bottom edge in northern hemisphere)
194 @type min_lat: C{float}
195 @param min_lon: minimum longitude (left edge in western hemisphere)
196 @type min_lon: C{float}
197 @param max_lat: maximum latitude (top edge in northern hemisphere)
198 @type max_lat: C{float}
199 @param max_lon: maximum longitude (right edge in western hemisphere)
200 @type max_lon: C{float}
201 """
202 self.min_lat = float(min_lat)
203 self.min_lon = float(min_lon)
204 self.max_lat = float(max_lat)
205 self.max_lon = float(max_lon)
206
208 """
209 Calculate the width, in statue miles.
210
211 @return: width, in statute miles
212 @rtype: C{float}
213 """
214 return calculate_distance(self.min_lat, self.min_lon,
215 self.min_lat, self.max_lon)
216
218 """
219 Calculate the height, in statue miles.
220
221 @return: height, in statute miles
222 @rtype: C{float}
223 """
224 return calculate_distance(self.min_lat, self.min_lon,
225 self.max_lat, self.min_lon)
226
228 """
229 Calculate the area, in square statue miles.
230
231 @return: area, in square miles
232 @rtype: C{float}
233 """
234 return self.width() * self.height()
235
237 """
238 Is the point (C{lat},C{lon}) in this box?
239
240 @param lat: latitude
241 @type lat: C{float}
242 @param lon: longitude
243 @type lon: C{float}
244
245 @return: C{True} or C{False}
246 @rtype: C{boolean}
247 """
248 lat = float(lat)
249 lon = float(lon)
250 if _between(lat, self.min_lat, self.max_lat) and \
251 _between(lon, self.min_lon, self.max_lon):
252 return True
253 return False
254
255 - def resize(self, new_width, new_height):
256 """
257 Redo the corner points of this box to reflect new C{width} and
258 C{height}, maintaining the same center point as this box currently
259 has.
260
261 @param new_width: new width of box
262 @type new_width: C{float}
263 @param new_height: new height of box
264 @type new_height: C{float}
265 """
266 mid_lat = (self.min_lat + self.max_lat) / 2.0
267 mid_lon = (self.min_lon + self.max_lon) / 2.0
268
269 dist = new_height / 2.0
270 self.min_lat, lon = pt_dist_from_pt(mid_lat, mid_lon, dist, 180)
271 self.max_lat, lon = pt_dist_from_pt(mid_lat, mid_lon, dist, 0)
272
273 dist = new_width / 2.0
274 lat, self.min_lon = pt_dist_from_pt(mid_lat, mid_lon, dist, 270)
275 lat, self.max_lon = pt_dist_from_pt(mid_lat, mid_lon, dist, 90)
276
278 """
279 Expand this box to include the point (C{lat},C{lon}).
280
281 @param lat: latitude of point to include
282 @type lat: C{float}
283 @param lon: longitude of point to include
284 @type lon: C{float}
285 """
286 lat = float(lat)
287 lon = float(lon)
288 self.min_lat = min(self.min_lat, lat)
289 self.min_lon = min(self.min_lon, lon)
290 self.max_lat = max(self.max_lat, lat)
291 self.max_lon = max(self.max_lon, lon)
292
294 """
295 Expand this box to include the corners of the given box.
296
297 @param box: box to expand to
298 @type box: L{Box}
299 """
300 self.min_lat = min(self.min_lat, box.min_lat)
301 self.min_lon = min(self.min_lon, box.min_lon)
302 self.max_lat = max(self.max_lat, box.max_lat)
303 self.max_lon = max(self.max_lon, box.max_lon)
304