def osgb_to_lonlat(osgb_str, model='OSGB36'): """ Convert an Ordinance Survey reference to a longitude and latitude. :Parameters: osgb_str An Ordnance Survey grid reference in "letter-number" format. Case and spaces are cleaned up by this function, and resolution automatically detected, so that so that ``TM114 525``, ``TM114525``, and ``TM 11400 52500`` are all recognised and identical. model 'OSGB36' or 'WGS84'. Default 'OSGB36'. :Returns: The longitude and latitude of the grid reference, according to the chosen model. For example:: # just outside Ipswich, about 1.088975 52.129892 >>> osgb_to_lonlat('TM114 525') (1.088975, 52.129892) # accepts poor formating >>> osgb_to_lonlat(' TM 114525 ') (1.088975, 52.129892) # accepts higher resolution >>> osgb_to_lonlat('TM1140052500') (1.088975, 52.129892) """ return tuple( reversed(osgb.grid_to_ll(osgb.parse_grid(osgb_str), model=model)))
def osgb_to_lonlat(osgb_str, model='OSGB36'): """ Convert an Ordinance Survey reference to a longitude and latitude. :Parameters: osgb_str An Ordnance Survey grid reference in "letter-number" format. Case and spaces are cleaned up by this function, and resolution automatically detected, so that so that ``TM114 525``, ``TM114525``, and ``TM 11400 52500`` are all recognised and identical. model OSGB36 or WGS84 :Returns: The longitude and latitude of the grid reference, according to the chosen model. For example:: # just outside Ipswich, about 1.088975 52.129892 >>> lon1, lat1 = osgb_to_lonlat ('TM114 525') >>> 1.0889 < lon1 < 1.0890 True >>> 52.1298 < lat1 < 52.1299 True >>> (round(lon1, 14), round(lat1, 14)) (1.08897495610794, 52.12989202825308) # accepts poor formating >>> lon2, lat2 = osgb_to_lonlat (' TM 114525 ') >>> lon2 == lon1 True >>> lat2 == lat1 True # accepts higher resolution >>> lon3, lat3 = osgb_to_lonlat ('TM1140052500') >>> 1.0889 < lon3 < 1.0890 True >>> 52.1298 < lat3 < 52.1299 True >>> (round(lon3, 14), round(lat3, 14)) (1.08897495610794, 52.12989202825308) """ (e, n) = osgb.parse_grid(osgb_str) (lat, lon) = osgb.grid_to_ll(e, n, model=model) return (lon, lat)
def osgb_to_lonlat(osgb_str, model='OSGB36'): """ Convert an Ordinance Survey reference to a longitude and latitude. :Parameters: osgb_str An Ordnance Survey grid reference in "letter-number" format. Case and spaces are cleaned up by this function, and resolution automatically detected, so that so that ``TM114 525``, ``TM114525``, and ``TM 11400 52500`` are all recognised and identical. model 'OSGB36' or 'WGS84'. Default 'OSGB36'. :Returns: The longitude and latitude of the grid reference, according to the chosen model. For example:: # just outside Ipswich, about 1.088975 52.129892 >>> lon1, lat1 = osgb_to_lonlat('TM114 525') >>> 1.0889 < lon1 < 1.0890 True >>> 52.1298 < lat1 < 52.1299 True >>> (round(lon1, 14), round(lat1, 14)) (1.08897495610794, 52.12989202825308) # accepts poor formating >>> lon2, lat2 = osgb_to_lonlat(' TM 114525 ') >>> lon2 == lon1 True >>> lat2 == lat1 True # accepts higher resolution >>> lon3, lat3 = osgb_to_lonlat('TM1140052500') >>> 1.0889 < lon3 < 1.0890 True >>> 52.1298 < lat3 < 52.1299 True >>> (round(lon3, 14), round(lat3, 14)) (1.08897495610794, 52.12989202825308) """ (e, n) = osgb.parse_grid(osgb_str) (lat, lon) = osgb.grid_to_ll(e, n, model=model) return (lon, lat)
def test_all(chatty=False): for k in sorted(test_input): (lat, lon) = osgb.grid_to_ll(*test_input[k]) phi = math.radians(lat) one_lat_in_mm = 111132954 - 559822 * math.cos( 2 * phi) + 1175 * math.cos(4 * phi) one_lon_in_mm = 1000 * (3.141592653589793 / 180) * (6378137 * math.cos( phi)) / math.sqrt(1 - 0.006694380004260827 * math.sin(phi)**2) delta_lat = lat - expected_output[k][0] delta_lon = lon - expected_output[k][1] delta_lat_mm = delta_lat * one_lat_in_mm delta_lon_mm = delta_lon * one_lon_in_mm if chatty: print('Test point {} dLat: {:+.3f} mm dLon: {:+.3f} mm'.format( k, delta_lat_mm, delta_lon_mm)) assert abs(delta_lat_mm) < acceptable_error_mm assert abs(delta_lon_mm) < acceptable_error_mm
# Starting making the MP file print( 'prologues := 3; outputtemplate := "%j.eps"; beginfig(1); defaultfont := "phvr8r";', file=plotter) # sides and insets will have anything in if we chose one or more series for k in sides + insets: print("fill {} withcolor (0.98, 0.906, 0.71);".format(path_for[k]), file=plotter) if args.error: for x in range(70): e = x * 10000 + 5000 for y in range(125): n = y * 10000 + 5000 (ee, nn) = osgb.ll_to_grid(*osgb.grid_to_ll(e, n)) h = math.sqrt((e - ee)**2 + (n - nn)**2) if h > 0: print( 'drawdot ({:.1f}, {:.1f}) withpen pencircle scaled 4 withcolor {:.2f}[white, red];' .format(e / scale, n / scale, h * 100), file=plotter) print( 'label.rt("Round trip error (mm)" infont defaultfont scaled 0.6, ({:.1f}, {:.1f}));' .format(-176500 / scale, 1255000 / scale), file=plotter) for i in range(6): e = -120000 - i * 10000 n = 1245000 print(
#! /usr/bin/env python3 import argparse import osgb if __name__ == "__main__": expected = (52+39/60+27.2531/3600, 1+43/60+4.5177/3600) got = osgb.grid_to_ll(651409.903, 313177.270, 'OSGB36') print(expected) print(got)
# open a tempory file for MP plotter = tempfile.NamedTemporaryFile(mode='wt', prefix='plot_maps_', suffix='.mp', dir='.', delete=False) # Starting making the MP file print('prologues := 3; outputtemplate := "%j.eps"; beginfig(1); defaultfont := "phvr8r";', file=plotter) # sides and insets will have anything in if we chose one or more series for k in sides + insets: print("fill {} withcolor (0.98, 0.906, 0.71);".format(path_for[k]), file=plotter) if args.error: for x in range(70): e = x * 10000 + 5000 for y in range(125): n = y * 10000 + 5000 (ee, nn) = osgb.ll_to_grid(*osgb.grid_to_ll(e, n)) h = math.sqrt((e-ee)**2+(n-nn)**2) if h > 0: print('drawdot ({:.1f}, {:.1f}) withpen pencircle scaled 4 withcolor {:.2f}[white, red];'.format(e/scale, n/scale, h*100), file=plotter) print('label.rt("Round trip error (mm)" infont defaultfont scaled 0.6, ({:.1f}, {:.1f}));'.format(-176500/scale, 1255000/scale), file=plotter) for i in range(6): e = -120000 - i * 10000 n = 1245000 print('drawdot ({:.1f}, {:.1f}) withpen pencircle scaled 4 withcolor {:.2f}[white, red];'.format(e/scale, n/scale, i/5), file=plotter) print('label.bot("{}" infont defaultfont scaled 0.6, ({:.1f}, {:.1f}));'.format(2*i, e/scale, n/scale-2), file=plotter) if not args.nograt: print("drawoptions(withpen pencircle scaled 0.4);", file=plotter) for lon in range(-10, 3): points = []
latlon[1] = -latlon[1] else: latlon = list(get_likely_lon_lat(x) for x in agenda.split()) # if the arguments consists of just two likely looking numbers... # You can't just say "all(floats)" because 0 is a valid Longitude if len(latlon) == 2 and all(x is not None for x in latlon): (lon, lat) = sorted(latlon) # Lon is always less than Lat in OSGB (e, n) = osgb.ll_to_grid(lat, lon) (olat, olon) = (lat, lon) (oe, on) = osgb.ll_to_grid(lat, lon, 'OSGB36') else: print('>>', agenda) (e, n) = osgb.parse_grid(agenda) (lat, lon) = osgb.grid_to_ll(e, n) (oe, on) = (e, n) (olat, olon) = osgb.grid_to_ll(e, n, 'OSGB36') try: grid = osgb.format_grid(e, n) maps = osgb.sheet_keys(e, n) except osgb.gridder.Error: grid = '??' maps = None if maps: map_string = 'on sheets {}'.format(', '.join(maps)) else: map_string = '(not covered by any OSGB map)'
if __name__ == "__main__": parser = argparse.ArgumentParser() parser.add_argument("--putsomethinghere") args = parser.parse_args() print(''' prologues := 3; outputtemplate := "%j%c.eps"; beginfig(1); ''') for n in range(1200500, 500, -10000): for e in range(500, 700000, 10000): lat, lon = osgb.grid_to_ll(e, n) ee, nn = osgb.ll_to_grid(lat, lon) de = ee-e dn = nn-n hh = math.sqrt(de*de + dn*dn) #print('{:.3f}'.format(hh*100), end=' ') if hh > 0: print('drawdot ({}, {}) withpen pencircle scaled 4 withcolor {}[white, red];'.format(e/1000, n/1000, hh*100)) print() for lat in range(50, 61): print('draw') for lon in range(-9, 2): (e, n) = osgb.ll_to_grid(lat, lon)
help="Which map series? A: Landranger, B: Explorer, C: One-inch, ...") args = parser.parse_args() jason = { 'type': 'FeatureCollection', 'features': [], } polygons = collections.defaultdict(list) titles = dict() # Note that contrary to ISO 6709 GeoJSON wants lon before lat for k, m in osgb.map_locker.items(): if m.series == args.series: p = [list(reversed(osgb.grid_to_ll(e, n))) for e, n in m.polygon] polygons[m.number].append([p]) if m.parent == '': titles[m.number] = m.title # Polygon is an array of linear ring arrays # first is the ccw container, second and any subsequent are the clockwise holes # for maps there are *no* holes, so all Polygons are an array of one array. # Multipolygons are an array of Polygons, we use them for sheets with more than # one sheet for k in sorted(polygons): p = polygons[k] if len(p) > 1:
def test_wrong_model(): with pytest.raises(osgb.convert.UndefinedModelError): _ = osgb.grid_to_ll(428765, 114567, 'EDM50')
def test_no_northing(): with pytest.raises(osgb.convert.MissingArgumentError): _ = osgb.grid_to_ll(428765, None)