Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Allow 3km grid with tile name in metres (not km) #34

Open
wants to merge 5 commits into
base: master
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
71 changes: 46 additions & 25 deletions src/equi7grid/equi7grid.py
Original file line number Diff line number Diff line change
Expand Up @@ -99,20 +99,25 @@ class Equi7Grid(TiledProjectionSystem):
_static_tilecodes = ["T6", "T3", "T1"]
# supported grid spacing ( = the pixel sampling)
_static_sampling = [
1000, 800, 750, 600, 500, 400, 300, 250, 200, 150, 125, 100, 96, 80,
6000, 3000, 1000, 800, 750, 600, 500, 400, 300, 250, 200, 150, 125, 100, 96, 80,
75, 64, 60, 50, 48, 40, 32, 30, 25, 24, 20, 16, 10, 8, 5, 4, 2, 1
]

def __init__(self, sampling):
def __init__(self, sampling, tile_names_in_m=False):
"""
Initialises an Equi7Grid class for a specified sampling.

Parameters
----------
sampling : int
the grid sampling = size of pixels; in metres.
tile_names_in_m : bool, optional
controls whether the tile names are in metres or in km when > 1000m

"""

self._tile_names_in_m = tile_names_in_m

# check if the equi7grid.data have been loaded successfully
if Equi7Grid._static_data is None:
raise ValueError("cannot load Equi7Grid ancillary data!")
Expand All @@ -123,9 +128,10 @@ def __init__(self, sampling):
# initializing
super(Equi7Grid, self).__init__(sampling, tag='Equi7')
self.core.projection = 'multiple'
self.core.tile_names_in_m = tile_names_in_m

@staticmethod
def encode_sampling(sampling):
def encode_sampling(sampling, tile_names_in_m=False):
"""
provides a string representing the sampling (e.g. for the tilenames)

Expand All @@ -138,15 +144,20 @@ def encode_sampling(sampling):
-------
sampling_str : str
string representing the sampling
tile_names_in_m : bool, optional
controls whether the tile names are in metres or in km when > 1000m
"""
if sampling <= 999:
if tile_names_in_m:
sampling_str = str(sampling).rjust(3, '0')
if sampling >= 1000:
sampling_str = "".join((str(sampling / 1000.0)[0], 'K', str(sampling / 1000.0)[2]))
else:
if sampling <= 999:
sampling_str = str(sampling).rjust(3, '0')
if sampling >= 1000:
sampling_str = "".join((str(sampling / 1000.0)[0], 'K', str(sampling / 1000.0)[2]))
return sampling_str

@staticmethod
def decode_sampling(sampling_str):
def decode_sampling(sampling_str, tile_names_in_m=False):
"""
converts the string representing the sampling (e.g. from the tilenames)
to an integer value in metres
Expand All @@ -155,18 +166,23 @@ def decode_sampling(sampling_str):
----------
sampling_str : str
string representing the sampling
tile_names_in_m : bool, optional
controls whether the tile names are in metres or in km when > 1000m

Returns
-------
sampling : int
the grid sampling = size of pixels; in metres.
"""
if len(sampling_str) != 3:
raise ValueError('Resolution is badly defined!')
if sampling_str[1] == 'K':
sampling = int(sampling_str[0]) * 1000 + int(sampling_str[2]) * 100
else:
if tile_names_in_m:
sampling = int(sampling_str)
else:
if len(sampling_str) != 3:
raise ValueError('Resolution is badly defined!')
if sampling_str[1] == 'K':
sampling = int(sampling_str[0]) * 1000 + int(sampling_str[2]) * 100
else:
sampling = int(sampling_str)
return sampling

def define_subgrids(self):
Expand All @@ -178,6 +194,11 @@ def define_subgrids(self):
subgrids : dict of Equi7Subgrid
dict of all subgrids of the grid
"""
# Set the tile names in metres or in km
# Reinforce copying into self.core, as it's initialized in TiledProjectionSystem not in Equi7Grid so can't
# take this custom property at init time. This is a bit of a hack but its needed in Equi7Subgrid()
self.core.tile_names_in_m = self._tile_names_in_m

subgrids = dict()
for sg in self._static_subgrid_ids:
subgrids[sg] = Equi7Subgrid(self.core, sg)
Expand All @@ -204,9 +225,9 @@ def get_tiletype(self, sampling=None):

sampling = int(sampling)

# allowing sampling of [1000, 800, 750, 600, 500, 400, 300, 250, 200,
# allowing sampling of [6000, 3000, 1000, 800, 750, 600, 500, 400, 300, 250, 200,
# 150, 125, 100, 96, 80, 75, 64] metres
if ((sampling in range(64, 1001)) and (600000 % sampling == 0)):
if ((sampling in range(64, 6001)) and (600000 % sampling == 0)):
tilecode = "T6"
# allowing sampling of [60, 50, 48, 40, 32, 30, 25, 24, 20] metres
elif ((sampling in range(20, 61)) and (300000 % sampling == 0)):
Expand Down Expand Up @@ -370,7 +391,7 @@ def __init__(self, core, continent):
self.core = _core

# holds name of the subgrid
self.name = ''.join(('EQUI7_', continent, Equi7Grid.encode_sampling(core.sampling), 'M'))
self.name = ''.join(('EQUI7_', continent, Equi7Grid.encode_sampling(core.sampling, core.tile_names_in_m), 'M'))

# holds the extent of the subgrid in the lonlat-space
self.polygon_geog = create_geometry_from_wkt(data['zone_extent'], epsg=4326)
Expand Down Expand Up @@ -546,7 +567,7 @@ def encode_tilename(self, llx, lly, sampling, tilecode, shortform=False):
# gives long-form of tilename (e.g. "EU500M_E012N018T6")
tilename = "{}{}M_E{:03d}N{:03d}{}".format(
self.core.tag,
Equi7Grid.encode_sampling(sampling),
Equi7Grid.encode_sampling(sampling, self.core.tile_names_in_m),
int(llx) // 100000,
int(lly) // 100000,
tilecode)
Expand Down Expand Up @@ -688,29 +709,29 @@ def decode_tilename(self, tilename):
sampling = self.core.sampling

# allow long-form of tilename (e.g. "EU500M_E012N018T6")
elif len(tilename) == 17:
# tile_names_in_m True or False
else:
subgrid_id = tilename[0:2]
if subgrid_id != self.core.tag:
raise ValueError(self.msg1)
sampling = Equi7Grid.decode_sampling(tilename[2:5])
tilename_sampling = tilename[2:].split('M')
sampling = Equi7Grid.decode_sampling(tilename_sampling[0], self.core.tile_names_in_m)
tilename_remaining = tilename.split('_')[1]
if sampling != self.core.sampling:
raise ValueError(self.msg1)
tile_size_m = int(tilename[-1]) * 100000
tile_size_m = int(tilename_remaining[-1]) * 100000
if tile_size_m != self.core.tile_xsize_m:
raise ValueError(self.msg1)
llx = int(tilename[8:11])
llx = int(tilename_remaining[1:4])
if llx % tf:
raise ValueError(self.msg2)
lly = int(tilename[12:15])
lly = int(tilename_remaining[5:8])
if lly % tf:
raise ValueError(self.msg2)
tilecode = tilename[-2:]
tilecode = tilename_remaining[-2:]
if tilecode != self.core.tiletype:
raise ValueError(self.msg1)

# wrong length
else:
raise ValueError(self.msg1)

return subgrid_id, sampling, tile_size_m, llx * 100000, lly * 100000, tilecode

Expand Down
23 changes: 23 additions & 0 deletions tests/test_equi7grid.py
Original file line number Diff line number Diff line change
Expand Up @@ -222,6 +222,29 @@ def test_lonlat2ij_in_tile(self):
nptest.assert_equal(j, row_should)
nptest.assert_equal(tilename, tile_should)

def test_lonlat2ij_in_tile(self):
"""
Tests the tile name with option tile_names_in_m as True or False

"""
e7 = Equi7Grid(3000, tile_names_in_m=True)
column_should = 199
row_should = 0
tile_should = 'EU3000M_E048N012T6'
tilename, i, j = e7.lonlat2ij_in_tile(18.507, 44.571, lowerleft=True)
nptest.assert_equal(i, column_should)
nptest.assert_equal(j, row_should)
nptest.assert_equal(tilename, tile_should)

e7 = Equi7Grid(3000, tile_names_in_m=False)
column_should = 199
row_should = 0
tile_should = 'EU3K0M_E048N012T6'
tilename, i, j = e7.lonlat2ij_in_tile(18.507, 44.571, lowerleft=True)
nptest.assert_equal(i, column_should)
nptest.assert_equal(j, row_should)
nptest.assert_equal(tilename, tile_should)

def test_proj4_reprojection_accuracy(self):
"""
Tests the proj4 reproject accuracy by forward and backward reprojection.
Expand Down