def test_geographic_distance(self): actual = angles.geographic_distance(0., 0., 1., 0.) expected = 111194.87 # 60 nautical miles in kilometers self.assertAlmostEqual(actual, expected, 1) actual = angles.geographic_distance(0., 0.5, 0., -0.5) self.assertAlmostEqual(actual, expected, 1) actual = angles.geographic_distance(0., 0.5, 0., 0.5) self.assertAlmostEqual(actual, 0., 1)
def bounding_box(fcst, pad=0.1, lon_pad=None, lat_pad=None): lons = np.unique(fcst['longitude'].values) lats = np.unique(fcst['latitude'].values) lon_diffs = angles.angle_diff(lons[:, None], lons) lat_diffs = angles.angle_diff(lats[:, None], lats) western_most_ind = np.nonzero(np.all(lon_diffs >= 0., axis=0))[0] western_most = np.unique(lons[western_most_ind]).item() eastern_most_ind = np.nonzero(np.all(lon_diffs <= 0., axis=0))[0] eastern_most = np.unique(lons[eastern_most_ind]).item() northern_most_ind = np.nonzero(np.all(lat_diffs <= 0., axis=0))[0] northern_most = np.unique(lats[northern_most_ind]).item() southern_most_ind = np.nonzero(np.all(lat_diffs >= 0., axis=0))[0] southern_most = np.unique(lats[southern_most_ind]).item() # count the number of lons greater than and less than each lon # and take the difference. The longitude (or pair of lons) that # minimize this help us determine the median. This allows different # definitions of longitude. lon_rel_loc = np.abs(np.sum(lon_diffs >= 0., axis=0) - np.sum(lon_diffs <= 0., axis=0)) central_lons = lons[lon_rel_loc == np.min(lon_rel_loc)] # make sure the central two aren't too far apart. assert np.max(central_lons) - np.min(central_lons) < 90 median_lon = np.median(central_lons) lat_rel_loc = np.abs(np.sum(lat_diffs >= 0., axis=0) - np.sum(lat_diffs <= 0., axis=0)) central_lats = lats[lat_rel_loc == np.min(lat_rel_loc)] median_lat = np.median(central_lats) width = angles.geographic_distance(western_most, median_lat, eastern_most, median_lat) height = angles.geographic_distance(median_lon, northern_most, median_lon, southern_most) if lon_pad is None: lon_pad = pad * np.abs(angles.angle_diff(eastern_most, western_most)) if lat_pad is None: lat_pad = pad * np.abs(angles.angle_diff(northern_most, southern_most)) return {'llcrnrlon': western_most - lon_pad, 'urcrnrlon': eastern_most + lon_pad, 'urcrnrlat': northern_most + lat_pad, 'llcrnrlat': southern_most - lat_pad, 'width': width * (1. + 2 * pad), 'height': height * (1. + 2 * pad), 'lon_0': median_lon, 'lat_0': median_lat}