Skip to content

Commit cd86423

Browse files
committed
add option to retile areas with no sheets
1 parent 4ca1ca5 commit cd86423

File tree

2 files changed

+50
-6
lines changed

2 files changed

+50
-6
lines changed

README.md

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -190,11 +190,12 @@ The tool works in two stages. First, it calculates the full set of sheets that n
190190
In the second stage, it retiles the affected area. It uses the pull list to create a temporary virtual raster (`.vrt`), generates new base tiles for the affected region, and then reconstructs the upper-level tiles by pulling existing, unaffected tiles from the PMTiles source.
191191

192192
```bash
193-
retile --retile-list-file <file> --bounds-file <file> [--max-zoom <zoom>] [--tiffs-dir <dir>] [--tiles-dir <dir>] [--from-source <source>] [--sheets-to-pull-list-outfile <file>] [--num-parallel <processes>] [--tile-quality <quality>]
193+
retile --retile-list-file <file> --bounds-file <file> [--dummy-bounds-file <file>] [--max-zoom <zoom>] [--tiffs-dir <dir>] [--tiles-dir <dir>] [--from-source <source>] [--sheets-to-pull-list-outfile <file>] [--num-parallel <processes>] [--tile-quality <quality>]
194194
```
195195

196196
- `--retile-list-file`: File containing the list of sheets to retile. (Required)
197197
- `--bounds-file`: GeoJSON file containing the list of available sheets and their geographic bounds. (Required)
198+
- `--dummy-bounds-file`: GeoJSON file containing geographic bounds of areas that need to be updated. These areas might not have any new sheets. (Optional)
198199
- `--max-zoom`: Maximum zoom level to create tiles for. Defaults to the max zoom from the source if `--from-source` is provided, otherwise it is required.
199200
- `--tiffs-dir`: Directory where the GeoTIFFs are located. (Required if not in pull-list generation mode)
200201
- `--tiles-dir`: Directory where the tiles will be created. (Required if not in pull-list generation mode)

topo_map_processor/tools/retile.py

Lines changed: 48 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -4,6 +4,7 @@
44
import sys
55
import json
66
import argparse
7+
import tempfile
78

89
import time
910
import subprocess
@@ -319,17 +320,22 @@ def check_sheets(sheets_to_pull, tiffs_dir):
319320
raise Exception(f'missing files {missing}')
320321

321322

322-
def get_sheet_data(bounds_fname):
323+
def get_sheet_data(bounds_fname, dummy=False):
323324

324325
index_file = Path(bounds_fname)
325326
if not index_file.exists():
326327
raise Exception(F'missing index file at {bounds_fname}')
327328

328329
index_data = json.loads(index_file.read_text())
329330

331+
dummy_count = 0
330332
sheets_to_box = {}
331333
for f in index_data['features']:
332-
sheet_no = f['properties']['id']
334+
if not dummy:
335+
sheet_no = f['properties']['id']
336+
else:
337+
sheet_no = f'dummy_{dummy_count}'
338+
dummy_count += 1
333339
geom = shape(f['geometry'])
334340
xmin, ymin, xmax, ymax = geom.bounds
335341
box = mercantile.LngLatBbox(xmin, ymin, xmax, ymax)
@@ -354,33 +360,61 @@ def get_base_tile_sheet_mappings(sheets_to_box, base_zoom):
354360

355361

356362

357-
def assess_sheet_requirements(retile_list_file, bounds_file, max_zoom):
363+
def assess_sheet_requirements(retile_list_file, bounds_file, dummy_bounds_file, max_zoom):
358364

359365
retile_sheets = retile_list_file.read_text().split('\n')
360366
retile_sheets = set([ r.strip().replace('.tif', '') for r in retile_sheets if r.strip() != '' ])
361367

362368
print('getting base tiles to sheet mapping')
363369
sheets_to_box = get_sheet_data(bounds_file)
370+
dummy_sheets_to_box = {}
371+
if dummy_bounds_file:
372+
dummy_sheets_to_box = get_sheet_data(dummy_bounds_file, dummy=True)
373+
sheets_to_box.update(dummy_sheets_to_box)
374+
364375
sheets_to_base_tiles, base_tiles_to_sheets = get_base_tile_sheet_mappings(sheets_to_box, max_zoom)
365376

366377
print('calculating sheets to pull')
367378
affected_base_tiles = set()
368379
for sheet_no in retile_sheets:
369380
affected_base_tiles.update(sheets_to_base_tiles[sheet_no])
381+
for sheet_no in dummy_sheets_to_box.keys():
382+
affected_base_tiles.update(sheets_to_base_tiles[sheet_no])
370383

371384
sheets_to_pull = set()
372385
for tile in affected_base_tiles:
373386
to_add = base_tiles_to_sheets[tile]
374387
for sheet in to_add:
375-
sheets_to_pull.add(sheet + '.tif')
388+
if sheet not in dummy_sheets_to_box:
389+
sheets_to_pull.add(sheet + '.tif')
376390

377391
return sheets_to_pull, affected_base_tiles
378392

393+
def create_dummy_sheets(dummy_bounds_file, tiffs_dir):
394+
print('creating dummy sheets')
395+
dummy_sheets_to_box = get_sheet_data(dummy_bounds_file, dummy=True)
396+
397+
for sheet_no, box in dummy_sheets_to_box.items():
398+
file = tiffs_dir.joinpath(f'{sheet_no}.tif')
399+
if file.exists():
400+
continue
401+
402+
west, south, east, north = box.west, box.south, box.east, box.north
403+
temp_file = Path(tempfile.mktemp(suffix='.tif'))
404+
cmd = f'gdal_create -of GTiff -a_srs EPSG:4326 -a_ullr {west} {north} {east} {south} -a_nodata 0 -ot Byte -co COMPRESS=LZW -bands 3 -burn 0 0 0 -outsize 256 256 {temp_file}'
405+
run_external(cmd)
406+
temp_file_1 = Path(tempfile.mktemp(suffix='.tif'))
407+
cmd = f'gdalwarp -dstalpha -t_srs EPSG:3857 -co COMPRESS=LZW {temp_file} {temp_file_1}'
408+
run_external(cmd)
409+
cmd = f'gdal_translate -co TILING_SCHEME=GoogleMapsCompatible -co COMPRESS=JPEG -co QUALITY=100 --config GDAL_TIFF_INTERNAL_MASK YES -b 1 -b 2 -b 3 -mask 4 --config GDAL_CACHEMAX 512 -of COG {temp_file_1} {file}'
410+
run_external(cmd)
411+
379412
def retile_main(args):
380413

381414
parser = argparse.ArgumentParser()
382415
parser.add_argument('--retile-list-file', required=True, help='File containing list of sheets to retile')
383416
parser.add_argument('--bounds-file', required=True, help='Geojson file containing list of available sheets and their georaphic bounds')
417+
parser.add_argument('--dummy-bounds-file', required=False, help='Geojson file containing georaphic bounds of areas that need to be updated, these areas might not have any new sheets')
384418
parser.add_argument('--max-zoom', type=int, help='Maximum zoom level to create tiles for, needed only when --from-source is not provided')
385419
parser.add_argument('--sheets-to-pull-list-outfile', default=None,
386420
help='Output into which we write the list of sheet that need to be pulled, if set, the script ends after it created the list file')
@@ -400,6 +434,12 @@ def retile_main(args):
400434
if not bounds_file.exists():
401435
parser.error(f'Bounds file {args.bounds_file} does not exist')
402436

437+
dummy_bounds_file = None
438+
if args.dummy_bounds_file:
439+
dummy_bounds_file = Path(args.dummy_bounds_file)
440+
if not dummy_bounds_file.exists():
441+
parser.error(f'Dummy bounds file {args.dummy_bounds_file} does not exist')
442+
403443

404444
if not args.sheets_to_pull_list_outfile:
405445
missing = []
@@ -430,7 +470,7 @@ def retile_main(args):
430470
print(f'--max-zoom argument is ignored when --from-source is set, using max zoom from original source: {max_zoom}')
431471

432472
# calculate the sheets to pull and affected base tiles
433-
sheets_to_pull, affected_base_tiles = assess_sheet_requirements(retile_list_file, bounds_file, max_zoom)
473+
sheets_to_pull, affected_base_tiles = assess_sheet_requirements(retile_list_file, bounds_file, dummy_bounds_file, max_zoom)
434474

435475
if args.sheets_to_pull_list_outfile is not None:
436476
Path(args.sheets_to_pull_list_outfile).write_text('\n'.join(sheets_to_pull) + '\n')
@@ -443,6 +483,9 @@ def retile_main(args):
443483
print('check the sheets availability')
444484
check_sheets(sheets_to_pull, tiffs_dir)
445485

486+
if dummy_bounds_file is not None:
487+
create_dummy_sheets(dummy_bounds_file, tiffs_dir)
488+
446489
metadata = orig_source.get_metadata()
447490
tile_extension = metadata['format']
448491
if tile_extension == 'jpg':

0 commit comments

Comments
 (0)