Package sabx10 :: Package oxm :: Module geom
[hide private]
[frames] | no frames]

Source Code for Module sabx10.oxm.geom

  1  ############################################################################### 
  2  # 
  3  # sabx10.oxm - an SABX file manipulation library 
  4  # Copyright (C) 2009, 2010 Jay Farrimond (jay@sabikerides.com) 
  5  # 
  6  # This file is part of sabx10.oxm. 
  7  # 
  8  # sabx10.oxm is free software: you can redistribute it and/or modify it under 
  9  # the terms of the GNU Lesser General Public License as published by the Free 
 10  # Software Foundation, either version 3 of the License, or (at your option) any 
 11  # later version. 
 12  # 
 13  # sabx10.oxm is distributed in the hope that it will be useful, but WITHOUT ANY 
 14  # WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR 
 15  # A PARTICULAR PURPOSE.  See the GNU Lesser General Public License for more 
 16  # details. 
 17  # 
 18  # You should have received a copy of the GNU Lesser General Public License 
 19  # along with sabx10.oxm.  If not, see <http://www.gnu.org/licenses/>. 
 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   
27 -class Point(object):
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
81 - def calculate_distance(self, point):
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
97 - def pt_dist_from(self, distance, true_course):
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
118 -def _pt_pairs(pts):
119 pt_from = pts[0] 120 for pt_to in pts[1:]: 121 yield pt_from, pt_to 122 pt_from = pt_to
123
124 -class Line(object):
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
133 - def __init__(self, waypoints):
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
142 - def calc_length(self):
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
154 - def find_lowest_highest(self):
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
168 -def _between(check, left, right):
169 if (check > left and check < right) or \ 170 (check > right and check < left): 171 return True 172 return False
173
174 -class Box(object):
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
207 - def width(self):
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
217 - def height(self):
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
227 - def area(self):
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
236 - def is_pt_in_box(self, lat, lon):
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) # down 271 self.max_lat, lon = pt_dist_from_pt(mid_lat, mid_lon, dist, 0) # up 272 273 dist = new_width / 2.0 274 lat, self.min_lon = pt_dist_from_pt(mid_lat, mid_lon, dist, 270) # left 275 lat, self.max_lon = pt_dist_from_pt(mid_lat, mid_lon, dist, 90) # right
276
277 - def expand_to_point(self, lat, lon):
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
293 - def expand_to_box(self, box):
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