Skip to content

Commit 13c0924

Browse files
committed
Merge branch 'dev' into rc
2 parents 11636d0 + 2daad9c commit 13c0924

24 files changed

Lines changed: 1013 additions & 672 deletions

docker/Dockerfile.worker

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -12,7 +12,7 @@ ENV VERSION=${VERSION:-${DOCKER_TAG:-master}}
1212
RUN echo "$VERSION" >/etc/qc_tool_version.txt \
1313
&& apt-get -y update \
1414
&& apt-get -y upgrade \
15-
&& apt-get -y install wget unzip
15+
&& apt-get -y install wget unzip time
1616

1717
# Install python and bootstrap pip.
1818
RUN cd /usr/local/src \
@@ -24,7 +24,7 @@ RUN cd /usr/local/src \
2424
RUN apt-get -y install gdal-bin python3-gdal \
2525
&& apt-get -y install python3-psycopg2 \
2626
&& pip3 install numpy \
27-
&& pip3 install scikit-image reportlab \
27+
&& pip3 install scikit-image reportlab requests \
2828
&& pip3 install bottle \
2929
&& pip3 install supervisor
3030

src/qc_tool/raster/inspire.py

Lines changed: 27 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -2,20 +2,35 @@
22
# -*- coding: utf-8 -*-
33

44

5-
"""
6-
The last implementation used external inspire validation service at `<http://inspire-geoportal.ec.europa.eu/GeoportalProxyWebServices/resources/INSPIREResourceTester>`_.
7-
Such service has been discontinued.
8-
9-
Until new implementation come, the check always results in cancelled.
10-
Cancelled result does not prevent later submittion of the delivery.
11-
This way it may be avoided adapting and hampering already stable product definitions.
12-
"""
13-
14-
155
DESCRIPTION = "Metadata are in accord with INSPIRE specification."
166
IS_SYSTEM = False
177

188

9+
def locate_xml_file(layer_filepath):
10+
# The INSPIRE XML file can be LAYER.xml or LAYER.tif.xml or LAYER_metadata.xml.
11+
# The file can also be located in a "metadata" subdirectory.
12+
for xml_filepath in [layer_filepath.parent.joinpath(layer_filepath.name + ".xml"),
13+
layer_filepath.parent.joinpath(layer_filepath.stem + ".xml"),
14+
layer_filepath.parent.joinpath(layer_filepath.stem + "_metadata.xml"),
15+
layer_filepath.parent.joinpath("metadata", layer_filepath.name + ".xml"),
16+
layer_filepath.parent.joinpath("metadata", layer_filepath.stem + ".xml"),
17+
layer_filepath.parent.joinpath("metadata", layer_filepath.stem + "_metadata.xml")]:
18+
if xml_filepath.exists():
19+
return xml_filepath
20+
return None
21+
22+
1923
def run_check(params, status):
20-
"""The check always results in cancelled."""
21-
status.cancelled("The check is not implemented yet.")
24+
from qc_tool.vector.helper import do_inspire_check
25+
from qc_tool.raster.helper import do_raster_layers
26+
27+
for layer_def in do_raster_layers(params):
28+
# Verify if there is any xml INSPIRE metadata file to check.
29+
xml_filepath = locate_xml_file(layer_def["src_filepath"])
30+
if xml_filepath is None:
31+
status.failed("Metadata file for {:s} has not been found.".format(layer_def["src_filepath"].name))
32+
return
33+
34+
# Validate the xml file using INSPIRE validator service
35+
export_prefix = "s{:02d}_{:s}_inspire".format(params["step_nr"], layer_def["src_filepath"].stem)
36+
do_inspire_check(xml_filepath, export_prefix, params["output_dir"], status)

src/qc_tool/raster/mmu.py

Lines changed: 28 additions & 17 deletions
Original file line numberDiff line numberDiff line change
@@ -79,6 +79,22 @@ def patch_touches_cell_with_value(coordinates, tile, neighbour_values):
7979
return True
8080
return False
8181

82+
def patch_touches_raster_edge(coordinates, raster_nrows, raster_ncols):
83+
"""
84+
Takes a list of [row, column] cell coordinates and inspects if at least one of the coordinates
85+
is located exactly at the specified edge of the tile.
86+
This function can be used for detecting patches touching the raster bounding box.
87+
:param coordinates: The patch of same-value raster cells.
88+
:param raster_nrows: Number of rows in the whole source raster.
89+
:param raster_ncols: Number of columns in the whole source raster.
90+
:return: True if at least one cell in the patch is located at source raster edge.
91+
"""
92+
for coor in coordinates:
93+
if coor[0] == 0 or coor[1] == 0 or coor[0] == raster_ncols - 1 or coor[1] == raster_nrows - 1:
94+
return True
95+
return False
96+
97+
8298
def export(regions, raster_ds, gpkg_filepath):
8399
"""
84100
Exports a list of lessMMU region dictionaries to geopackage.
@@ -216,22 +232,22 @@ def run_check(params, status):
216232
write_percent(percent_filepath, progress_percent)
217233

218234
if tileRow == 0:
219-
# first row
235+
# First row
220236
yOff = 0
221237
yOffInner = 0
222238
yOffRelative = 0
223239
block_height = BLOCKSIZE + buffer_width
224240
block_height_inner = BLOCKSIZE
225241
else:
226-
# middle row
242+
# Middle row
227243
yOff = tileRow * BLOCKSIZE
228244
yOffInner = yOff + buffer_width
229245
yOffRelative = buffer_width
230246
block_height = blocksize_with_buffer
231247
block_height_inner = BLOCKSIZE
232248

233249
if tileRow == last_row:
234-
# special case for last row - adjust block width
250+
# Last row is a special case - block width must be adjusted.
235251
block_height = nRasterRows - yOff
236252
block_height_inner = block_height - buffer_width
237253

@@ -242,22 +258,22 @@ def run_check(params, status):
242258
# TILES: ITERATE COLUMNS
243259
for tileCol in range(nTileCols):
244260
if tileCol == 0:
245-
# first column
261+
# First column
246262
xOff = 0
247263
xOffInner = 0
248264
xOffRelative = 0
249265
block_width = BLOCKSIZE + buffer_width
250266
block_width_inner = BLOCKSIZE
251267
else:
252-
# middle column
268+
# Middle column
253269
xOff = tileCol * BLOCKSIZE
254270
xOffInner = xOff + buffer_width
255271
xOffRelative = buffer_width
256272
block_width = blocksize_with_buffer
257273
block_width_inner = BLOCKSIZE
258274

259275
if tileCol == last_col:
260-
# special case for last column - adjust block width
276+
# Last column is a special case - block width must be adjusted.
261277
block_width = nRasterCols - xOff
262278
block_width_inner = block_width - buffer_width
263279

@@ -286,7 +302,6 @@ def run_check(params, status):
286302
tile_inner = tile_buffered[yOffRelative: yOffRelative + block_height_inner, xOffRelative: xOffRelative + block_width_inner]
287303

288304
# read inner array (without buffer)
289-
# tile_inner = ds.ReadAsArray(xOffInner, yOffInner, block_width_inner, block_height_inner)
290305

291306
# label the inner array and find patches < MMU
292307
labels_inner = measure.label(tile_inner, background=NODATA, neighbors=4)
@@ -327,6 +342,8 @@ def run_check(params, status):
327342
regions_lessMMU_except.append(lessMMU_info)
328343
elif patch_touches_cell_with_value(r.coords, tile_inner, neighbour_exclude_values):
329344
regions_lessMMU_except.append(lessMMU_info)
345+
elif patch_touches_raster_edge(absolute_coords, nRasterRows, nRasterCols):
346+
regions_lessMMU_except.append(lessMMU_info)
330347
else:
331348
regions_lessMMU.append(lessMMU_info)
332349

@@ -338,10 +355,7 @@ def run_check(params, status):
338355
msg = msg.format(tr=tileRow, ntr=nTileRows, tc=tileCol, w=block_width, h=block_height)
339356
write_progress(progress_filepath, msg)
340357

341-
# read the outer array expanded by buffer with width=number of pixels in MMU
342-
343-
# no need, already read ...
344-
# tile_buffered = ds.ReadAsArray(xOff, yOff, block_width, block_height)
358+
# processing the outer array expanded by buffer with width=number of pixels in MMU
345359

346360
# optimization: set pixels not within buffer zone (deep inside outer array) to background.
347361
inner_buf_startcol = xOffRelative + MMU
@@ -352,11 +366,6 @@ def run_check(params, status):
352366
tile_buffered[inner_buf_startrow:inner_buf_endrow,
353367
inner_buf_startcol:inner_buf_endcol] = NODATA
354368

355-
# no need to reclassify, already reclassified ..
356-
# reclassify outer tile array if some patches should be grouped together
357-
# if use_reclassify:
358-
# tile_buffered = reclassify_values(tile_buffered, params["groupcodes"])
359-
360369
labels_buf = measure.label(tile_buffered, background=NODATA, neighbors=4)
361370
buf_regions = measure.regionprops(labels_buf)
362371
buf_regions_small = [r for r in buf_regions if r.area < MMU]
@@ -387,11 +396,13 @@ def run_check(params, status):
387396
"area": r_buf.area, "value": val,
388397
"coords": absolute_coords}
389398

390-
399+
# handling special cases (exception patches)
391400
if val in exclude_values:
392401
regions_lessMMU_except.append(lessMMU_info)
393402
elif patch_touches_cell_with_value(r_buf.coords, tile_buffered, neighbour_exclude_values):
394403
regions_lessMMU_except.append(lessMMU_info)
404+
elif patch_touches_raster_edge(absolute_coords, nRasterRows, nRasterCols):
405+
regions_lessMMU_except.append(lessMMU_info)
395406
else:
396407
regions_lessMMU.append(lessMMU_info)
397408

src/qc_tool/raster/unzip.py

Lines changed: 1 addition & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -2,13 +2,11 @@
22
# -*- coding: utf-8 -*-
33

44

5-
from qc_tool.vector.helper import do_unzip
6-
7-
85
DESCRIPTION = "Delivery file can be unzipped."
96
IS_SYSTEM = True
107

118

129
def run_check(params, status):
1310
# Raster layers are unzipped to the temporary directory r_unzip.d.
11+
from qc_tool.vector.helper import do_unzip
1412
do_unzip(params["filepath"], params["tmp_dir"].joinpath("r_unzip.d"), status)

0 commit comments

Comments
 (0)