Skip to content

Commit d1e84c1

Browse files
committed
Interpolate long line segments in lon,lat space.
New GSHHS versions simplify long national/state borders that are perfectly linear in geographic space. However, basemap assumes that these lines are already subsampled, and does the interpolation in between the two points in geographic space. This leads to extreme errors for long borders with only two points (e.g. the US/Canada border). Old GSHHS versions stored interpolated versions, so this is an issue that didn't come up in the past. To get around this, we'll interpolate long linear segments and store the interpolated versions.
1 parent 1efa3ad commit d1e84c1

File tree

2 files changed

+60
-4
lines changed

2 files changed

+60
-4
lines changed

utils/readboundaries.py

Lines changed: 29 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -21,6 +21,32 @@ def quantize(data,least_significant_digit):
2121
scale = pow(2.,bits)
2222
return numpy.around(scale*data)/scale
2323

24+
def interpolate_long_segments(coords, resolution):
25+
lookup_thresh = {'c': 0.5, 'l':0.1, 'i':0.05, 'h':0.01, 'f':0.005}
26+
thresh = lookup_thresh[resolution]
27+
spacing = thresh / 5.0
28+
29+
lons, lats = coords.T
30+
dist = np.hypot(np.diff(lons), np.diff(lats))
31+
32+
if np.all(dist <= thresh):
33+
return coords
34+
35+
out_lon, out_lat = [], []
36+
for i in np.arange(len(dist)):
37+
if dist[i] <= thresh:
38+
out_lon.append(lons[i])
39+
out_lat.append(lats[i])
40+
else:
41+
x = [0, dist[i]]
42+
new_x = np.arange(0, dist[i], spacing)
43+
out_lon.extend(np.interp(new_x, x, lons[i:i+2]))
44+
out_lat.extend(np.interp(new_x, x, lats[i:i+2]))
45+
46+
out_lon.append(lons[-1])
47+
out_lat.append(lats[-1])
48+
return np.column_stack([out_lon, out_lat]).astype(coords.dtype)
49+
2450
def get_coast_polygons(coastfile):
2551
polymeta = []; polybounds = []
2652
lats = []; lons = []
@@ -57,7 +83,7 @@ def get_coast_polygons(coastfile):
5783
polymeta2.append(meta[:-1] + [npts] + [meta[-1]])
5884
return polybounds, polymeta2
5985

60-
def get_boundary_lines(bdatfile):
86+
def get_boundary_lines(bdatfile, resolution):
6187
lons = []; lats = []; polybounds = []
6288
for line in open(bdatfile):
6389
if line.startswith('#'): continue
@@ -77,6 +103,7 @@ def get_boundary_lines(bdatfile):
77103
b[:,0] = lons; b[:,1] = lats
78104
if lsd is not None:
79105
b = quantize(b,lsd)
106+
b = interpolate_long_segments(b, resolution)
80107
polybounds.append(b)
81108
polymeta = []
82109
polybounds2 = []
@@ -113,7 +140,7 @@ def get_boundary_lines(bdatfile):
113140
f.close()
114141
f2.close()
115142

116-
poly, polymeta = get_boundary_lines(countryfile)
143+
poly, polymeta = get_boundary_lines(countryfile, resolution)
117144
f = open('../lib/mpl_toolkits/basemap/data/countries_'+resolution+'.dat','wb')
118145
f2 = open('../lib/mpl_toolkits/basemap/data/countriesmeta_'+resolution+'.dat','w')
119146
offset = 0

utils/readboundaries_shp.py

Lines changed: 31 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -30,6 +30,32 @@ def quantize(data,least_significant_digit):
3030
scale = pow(2.,bits)
3131
return np.around(scale*data)/scale
3232

33+
def interpolate_long_segments(coords, resolution):
34+
lookup_thresh = {'c': 0.5, 'l':0.1, 'i':0.05, 'h':0.01, 'f':0.005}
35+
thresh = lookup_thresh[resolution]
36+
spacing = thresh / 5.0
37+
38+
lons, lats = coords.T
39+
dist = np.hypot(np.diff(lons), np.diff(lats))
40+
41+
if np.all(dist <= thresh):
42+
return coords
43+
44+
out_lon, out_lat = [], []
45+
for i in np.arange(len(dist)):
46+
if dist[i] <= thresh:
47+
out_lon.append(lons[i])
48+
out_lat.append(lats[i])
49+
else:
50+
x = [0, dist[i]]
51+
new_x = np.arange(0, dist[i], spacing)
52+
out_lon.extend(np.interp(new_x, x, lons[i:i+2]))
53+
out_lat.extend(np.interp(new_x, x, lats[i:i+2]))
54+
55+
out_lon.append(lons[-1])
56+
out_lat.append(lats[-1])
57+
return np.column_stack([out_lon, out_lat]).astype(coords.dtype)
58+
3359
def get_coast_polygons(resolution):
3460
polymeta = []; polybounds = []
3561
for level in [1,2,3,5]:
@@ -88,13 +114,16 @@ def get_wdb_boundaries(resolution,level,rivers=False):
88114
for r,key in zip(rec,fields[1:]):
89115
attdict[key[0]]=r
90116
area = -1
91-
id = attdict['id']
92-
polymeta.append([-1,-1,south,north,len(lons),id])
117+
poly_id = attdict['id']
93118
b = np.empty((len(lons),2),np.float32)
94119
b[:,0] = lons; b[:,1] = lats
95120
if lsd is not None:
96121
b = quantize(b,lsd)
122+
b = interpolate_long_segments(b, resolution)
123+
124+
polymeta.append([-1,-1,south,north,len(b),poly_id])
97125
polybounds.append(b)
126+
98127
return polybounds, polymeta
99128

100129
# read in coastline data (only those polygons whose area > area_thresh).

0 commit comments

Comments
 (0)