topo_map_processor 0.1.16__tar.gz → 0.1.17__tar.gz
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- {topo_map_processor-0.1.16 → topo_map_processor-0.1.17}/PKG-INFO +61 -9
- {topo_map_processor-0.1.16 → topo_map_processor-0.1.17}/README.md +60 -8
- {topo_map_processor-0.1.16 → topo_map_processor-0.1.17}/pyproject.toml +1 -0
- {topo_map_processor-0.1.16 → topo_map_processor-0.1.17}/topo_map_processor/_version.py +2 -2
- {topo_map_processor-0.1.16 → topo_map_processor-0.1.17}/topo_map_processor/processor.py +77 -7
- {topo_map_processor-0.1.16 → topo_map_processor-0.1.17}/topo_map_processor/tools/collect_bounds.py +17 -8
- topo_map_processor-0.1.17/topo_map_processor/tools/create_force_redo_bounds.py +100 -0
- {topo_map_processor-0.1.16 → topo_map_processor-0.1.17}/topo_map_processor/tools/retile.py +10 -5
- {topo_map_processor-0.1.16 → topo_map_processor-0.1.17}/topo_map_processor/tools/retile_e2e.py +48 -70
- {topo_map_processor-0.1.16 → topo_map_processor-0.1.17}/.gitignore +0 -0
- {topo_map_processor-0.1.16 → topo_map_processor-0.1.17}/LICENSE +0 -0
- {topo_map_processor-0.1.16 → topo_map_processor-0.1.17}/topo_map_processor/__init__.py +0 -0
- {topo_map_processor-0.1.16 → topo_map_processor-0.1.17}/topo_map_processor/tools/__init__.py +0 -0
- {topo_map_processor-0.1.16 → topo_map_processor-0.1.17}/topo_map_processor/tools/tile.py +0 -0
- {topo_map_processor-0.1.16 → topo_map_processor-0.1.17}/topo_map_processor/tools/utils.py +0 -0
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
Metadata-Version: 2.4
|
|
2
2
|
Name: topo_map_processor
|
|
3
|
-
Version: 0.1.
|
|
3
|
+
Version: 0.1.17
|
|
4
4
|
Summary: Library for processing topographic maps
|
|
5
5
|
Project-URL: homepage, https://github.com/ramSeraph/topo_map_processor
|
|
6
6
|
Project-URL: repository, https://github.com/ramSeraph/topo_map_processor.git
|
|
@@ -249,28 +249,29 @@ This project provides several command-line tools to work with topographic maps.
|
|
|
249
249
|
Collects individual GeoJSONL bound files into a single GeoJSON FeatureCollection.
|
|
250
250
|
|
|
251
251
|
```bash
|
|
252
|
-
collect-bounds
|
|
252
|
+
collect-bounds -b <directory> -o <file> [-u] [-d <id1> <id2> ...]
|
|
253
253
|
```
|
|
254
254
|
|
|
255
|
-
- `--bounds-dir`: Directory containing GeoJSONL files. (Required)
|
|
256
|
-
- `--output-file`: Output GeoJSON file path. (Required)
|
|
257
|
-
- `--
|
|
255
|
+
- `-b`, `--bounds-dir`: Directory containing GeoJSONL files. (Required)
|
|
256
|
+
- `-o`, `--output-file`: Output GeoJSON file path. (Required)
|
|
257
|
+
- `-u`, `--update`: Update the output file in place. (Optional)
|
|
258
|
+
- `-d`, `--delete`: List of ids to delete from the output file (only available in update mode). (Optional)
|
|
258
259
|
|
|
259
260
|
#### `retile`
|
|
260
261
|
|
|
261
|
-
Retiles a specific list of sheets (GeoTIFFs) and updates the corresponding tiles in an existing tile set. It can determine which other sheets are affected and need to be pulled in to correctly retile the area.
|
|
262
|
+
Retiles a specific list of sheets (GeoTIFFs) or a specific area and updates the corresponding tiles in an existing tile set. It can determine which other sheets are affected and need to be pulled in to correctly retile the area.
|
|
262
263
|
|
|
263
264
|
The tool works in two stages. First, it calculates the full set of sheets that need to be processed (the "pull list"), which includes the sheets from the input list plus any adjacent sheets that share tiles. You can run the tool with `--sheets-to-pull-list-outfile` to generate this list and then exit. This is useful for fetching the required GeoTIFFs before proceeding.
|
|
264
265
|
|
|
265
266
|
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.
|
|
266
267
|
|
|
267
268
|
```bash
|
|
268
|
-
retile --retile-list-file <file> --bounds-file <file> [--
|
|
269
|
+
retile [--retile-list-file <file>] --bounds-file <file> [--force-redo-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>]
|
|
269
270
|
```
|
|
270
271
|
|
|
271
|
-
- `--retile-list-file`: File containing the list of sheets to retile. (
|
|
272
|
+
- `--retile-list-file`: File containing the list of sheets to retile. (Optional)
|
|
272
273
|
- `--bounds-file`: GeoJSON file containing the list of available sheets and their geographic bounds. (Required)
|
|
273
|
-
- `--
|
|
274
|
+
- `--force-redo-bounds-file`: GeoJSON file containing geographic bounds of areas that need to be updated. These areas might not have any new sheets. (Optional)
|
|
274
275
|
- `--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.
|
|
275
276
|
- `--tiffs-dir`: Directory where the GeoTIFFs are located. (Required if not in pull-list generation mode)
|
|
276
277
|
- `--tiles-dir`: Directory where the tiles will be created. (Required if not in pull-list generation mode)
|
|
@@ -279,6 +280,18 @@ retile --retile-list-file <file> --bounds-file <file> [--dummy-bounds-file <file
|
|
|
279
280
|
- `--num-parallel`: Number of parallel processes to use for tiling (default: number of CPU cores).
|
|
280
281
|
- `--tile-quality`: Quality of compression for webp and jpeg (default: 75).
|
|
281
282
|
|
|
283
|
+
#### `create-force-redo-bounds`
|
|
284
|
+
|
|
285
|
+
Creates a GeoJSON file that defines areas to be forcibly re-tiled, based on the differences between an old and a new bounds file. This is useful for identifying regions where map sheets may have been updated, moved, or removed.
|
|
286
|
+
|
|
287
|
+
```bash
|
|
288
|
+
create-force-redo-bounds --old-bounds-file <file> --new-bounds-file <file> --output-file <file>
|
|
289
|
+
```
|
|
290
|
+
|
|
291
|
+
- `--old-bounds-file`: The previous version of the bounds GeoJSON file. (Required)
|
|
292
|
+
- `--new-bounds-file`: The new version of the bounds GeoJSON file. (Required)
|
|
293
|
+
- `--output-file`: The path to write the output GeoJSON file, which will contain the bounds of the areas to be force-retiled. (Required)
|
|
294
|
+
|
|
282
295
|
#### `tile`
|
|
283
296
|
|
|
284
297
|
Creates web map tiles from a directory of GeoTIFF files. It combines them into a virtual raster (`.vrt`) for efficient processing.
|
|
@@ -316,6 +329,45 @@ GDAL_VERSION=$(gdalinfo --version | cut -d"," -f1 | cut -d" " -f2)
|
|
|
316
329
|
uvx --with numpy --with pillow --with gdal==$GDAL_VERSION --from topo_map_processor tile --help
|
|
317
330
|
```
|
|
318
331
|
|
|
332
|
+
### Map Update Workflow
|
|
333
|
+
|
|
334
|
+
This project provides a robust workflow for updating an existing tile set when map sheets are added, removed, or modified. The primary tools for this are `retile` and `create-force-redo-bounds`.
|
|
335
|
+
|
|
336
|
+
The general workflow is as follows:
|
|
337
|
+
|
|
338
|
+
1. **Generate New Bounds**: After processing new or updated map scans with the library, you will have a new set of COGs and `.geojsonl` bound files. Use the `collect-bounds` tool to create an updated `bounds.geojson` file that reflects the current state of your map collection.
|
|
339
|
+
|
|
340
|
+
2. **Identify Changes**: Use the `create-force-redo-bounds` tool to compare your old `bounds.geojson` with the new one.
|
|
341
|
+
|
|
342
|
+
```bash
|
|
343
|
+
create-force-redo-bounds --old-bounds-file old-bounds.geojson --new-bounds-file new-bounds.geojson --output-file force-redo.geojson
|
|
344
|
+
```
|
|
345
|
+
|
|
346
|
+
This command analyzes the differences:
|
|
347
|
+
* **Added Sheets**: If a map sheet exists in `new-bounds.geojson` but not in `old-bounds.geojson`.
|
|
348
|
+
* **Deleted Sheets**: If a sheet is in `old-bounds.geojson` but has been removed from `new-bounds.geojson`.
|
|
349
|
+
* **Modified Sheets**: If a sheet's geometry (boundary) or its content (indicated by a change in the `digest` property) has been updated.
|
|
350
|
+
|
|
351
|
+
The output, `force-redo.geojson`, will contain the geographic areas for all these changes, which tells the `retile` tool exactly which regions of the map need to be regenerated.
|
|
352
|
+
|
|
353
|
+
3. **Retile Affected Areas**: Use the `retile` tool to perform the update. The `force-redo.geojson` file you created contains all the information about what has changed, so a separate list of sheets is not required.
|
|
354
|
+
|
|
355
|
+
```bash
|
|
356
|
+
retile --bounds-file new-bounds.geojson \
|
|
357
|
+
--force-redo-bounds-file force-redo.geojson \
|
|
358
|
+
--from-source "existing-tiles/*.pmtiles" \
|
|
359
|
+
--tiffs-dir /path/to/cogs \
|
|
360
|
+
--tiles-dir /path/to/output/tiles
|
|
361
|
+
```
|
|
362
|
+
|
|
363
|
+
The `retile` tool will:
|
|
364
|
+
* Identify all GeoTIFFs needed to regenerate the affected tiles (including adjacent, unchanged sheets).
|
|
365
|
+
* Generate new base tiles for the changed areas.
|
|
366
|
+
* Copy unchanged tiles from your existing tile set (`--from-source`).
|
|
367
|
+
* Re-create parent tiles up the zoom levels.
|
|
368
|
+
|
|
369
|
+
This workflow ensures that your tile set is updated efficiently, without having to re-process the entire map collection.
|
|
370
|
+
|
|
319
371
|
## Contributing
|
|
320
372
|
|
|
321
373
|
Contributions are welcome! Please feel free to submit a pull request.
|
|
@@ -174,28 +174,29 @@ This project provides several command-line tools to work with topographic maps.
|
|
|
174
174
|
Collects individual GeoJSONL bound files into a single GeoJSON FeatureCollection.
|
|
175
175
|
|
|
176
176
|
```bash
|
|
177
|
-
collect-bounds
|
|
177
|
+
collect-bounds -b <directory> -o <file> [-u] [-d <id1> <id2> ...]
|
|
178
178
|
```
|
|
179
179
|
|
|
180
|
-
- `--bounds-dir`: Directory containing GeoJSONL files. (Required)
|
|
181
|
-
- `--output-file`: Output GeoJSON file path. (Required)
|
|
182
|
-
- `--
|
|
180
|
+
- `-b`, `--bounds-dir`: Directory containing GeoJSONL files. (Required)
|
|
181
|
+
- `-o`, `--output-file`: Output GeoJSON file path. (Required)
|
|
182
|
+
- `-u`, `--update`: Update the output file in place. (Optional)
|
|
183
|
+
- `-d`, `--delete`: List of ids to delete from the output file (only available in update mode). (Optional)
|
|
183
184
|
|
|
184
185
|
#### `retile`
|
|
185
186
|
|
|
186
|
-
Retiles a specific list of sheets (GeoTIFFs) and updates the corresponding tiles in an existing tile set. It can determine which other sheets are affected and need to be pulled in to correctly retile the area.
|
|
187
|
+
Retiles a specific list of sheets (GeoTIFFs) or a specific area and updates the corresponding tiles in an existing tile set. It can determine which other sheets are affected and need to be pulled in to correctly retile the area.
|
|
187
188
|
|
|
188
189
|
The tool works in two stages. First, it calculates the full set of sheets that need to be processed (the "pull list"), which includes the sheets from the input list plus any adjacent sheets that share tiles. You can run the tool with `--sheets-to-pull-list-outfile` to generate this list and then exit. This is useful for fetching the required GeoTIFFs before proceeding.
|
|
189
190
|
|
|
190
191
|
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.
|
|
191
192
|
|
|
192
193
|
```bash
|
|
193
|
-
retile --retile-list-file <file> --bounds-file <file> [--
|
|
194
|
+
retile [--retile-list-file <file>] --bounds-file <file> [--force-redo-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>]
|
|
194
195
|
```
|
|
195
196
|
|
|
196
|
-
- `--retile-list-file`: File containing the list of sheets to retile. (
|
|
197
|
+
- `--retile-list-file`: File containing the list of sheets to retile. (Optional)
|
|
197
198
|
- `--bounds-file`: GeoJSON file containing the list of available sheets and their geographic bounds. (Required)
|
|
198
|
-
- `--
|
|
199
|
+
- `--force-redo-bounds-file`: GeoJSON file containing geographic bounds of areas that need to be updated. These areas might not have any new sheets. (Optional)
|
|
199
200
|
- `--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.
|
|
200
201
|
- `--tiffs-dir`: Directory where the GeoTIFFs are located. (Required if not in pull-list generation mode)
|
|
201
202
|
- `--tiles-dir`: Directory where the tiles will be created. (Required if not in pull-list generation mode)
|
|
@@ -204,6 +205,18 @@ retile --retile-list-file <file> --bounds-file <file> [--dummy-bounds-file <file
|
|
|
204
205
|
- `--num-parallel`: Number of parallel processes to use for tiling (default: number of CPU cores).
|
|
205
206
|
- `--tile-quality`: Quality of compression for webp and jpeg (default: 75).
|
|
206
207
|
|
|
208
|
+
#### `create-force-redo-bounds`
|
|
209
|
+
|
|
210
|
+
Creates a GeoJSON file that defines areas to be forcibly re-tiled, based on the differences between an old and a new bounds file. This is useful for identifying regions where map sheets may have been updated, moved, or removed.
|
|
211
|
+
|
|
212
|
+
```bash
|
|
213
|
+
create-force-redo-bounds --old-bounds-file <file> --new-bounds-file <file> --output-file <file>
|
|
214
|
+
```
|
|
215
|
+
|
|
216
|
+
- `--old-bounds-file`: The previous version of the bounds GeoJSON file. (Required)
|
|
217
|
+
- `--new-bounds-file`: The new version of the bounds GeoJSON file. (Required)
|
|
218
|
+
- `--output-file`: The path to write the output GeoJSON file, which will contain the bounds of the areas to be force-retiled. (Required)
|
|
219
|
+
|
|
207
220
|
#### `tile`
|
|
208
221
|
|
|
209
222
|
Creates web map tiles from a directory of GeoTIFF files. It combines them into a virtual raster (`.vrt`) for efficient processing.
|
|
@@ -241,6 +254,45 @@ GDAL_VERSION=$(gdalinfo --version | cut -d"," -f1 | cut -d" " -f2)
|
|
|
241
254
|
uvx --with numpy --with pillow --with gdal==$GDAL_VERSION --from topo_map_processor tile --help
|
|
242
255
|
```
|
|
243
256
|
|
|
257
|
+
### Map Update Workflow
|
|
258
|
+
|
|
259
|
+
This project provides a robust workflow for updating an existing tile set when map sheets are added, removed, or modified. The primary tools for this are `retile` and `create-force-redo-bounds`.
|
|
260
|
+
|
|
261
|
+
The general workflow is as follows:
|
|
262
|
+
|
|
263
|
+
1. **Generate New Bounds**: After processing new or updated map scans with the library, you will have a new set of COGs and `.geojsonl` bound files. Use the `collect-bounds` tool to create an updated `bounds.geojson` file that reflects the current state of your map collection.
|
|
264
|
+
|
|
265
|
+
2. **Identify Changes**: Use the `create-force-redo-bounds` tool to compare your old `bounds.geojson` with the new one.
|
|
266
|
+
|
|
267
|
+
```bash
|
|
268
|
+
create-force-redo-bounds --old-bounds-file old-bounds.geojson --new-bounds-file new-bounds.geojson --output-file force-redo.geojson
|
|
269
|
+
```
|
|
270
|
+
|
|
271
|
+
This command analyzes the differences:
|
|
272
|
+
* **Added Sheets**: If a map sheet exists in `new-bounds.geojson` but not in `old-bounds.geojson`.
|
|
273
|
+
* **Deleted Sheets**: If a sheet is in `old-bounds.geojson` but has been removed from `new-bounds.geojson`.
|
|
274
|
+
* **Modified Sheets**: If a sheet's geometry (boundary) or its content (indicated by a change in the `digest` property) has been updated.
|
|
275
|
+
|
|
276
|
+
The output, `force-redo.geojson`, will contain the geographic areas for all these changes, which tells the `retile` tool exactly which regions of the map need to be regenerated.
|
|
277
|
+
|
|
278
|
+
3. **Retile Affected Areas**: Use the `retile` tool to perform the update. The `force-redo.geojson` file you created contains all the information about what has changed, so a separate list of sheets is not required.
|
|
279
|
+
|
|
280
|
+
```bash
|
|
281
|
+
retile --bounds-file new-bounds.geojson \
|
|
282
|
+
--force-redo-bounds-file force-redo.geojson \
|
|
283
|
+
--from-source "existing-tiles/*.pmtiles" \
|
|
284
|
+
--tiffs-dir /path/to/cogs \
|
|
285
|
+
--tiles-dir /path/to/output/tiles
|
|
286
|
+
```
|
|
287
|
+
|
|
288
|
+
The `retile` tool will:
|
|
289
|
+
* Identify all GeoTIFFs needed to regenerate the affected tiles (including adjacent, unchanged sheets).
|
|
290
|
+
* Generate new base tiles for the changed areas.
|
|
291
|
+
* Copy unchanged tiles from your existing tile set (`--from-source`).
|
|
292
|
+
* Re-create parent tiles up the zoom levels.
|
|
293
|
+
|
|
294
|
+
This workflow ensures that your tile set is updated efficiently, without having to re-process the entire map collection.
|
|
295
|
+
|
|
244
296
|
## Contributing
|
|
245
297
|
|
|
246
298
|
Contributions are welcome! Please feel free to submit a pull request.
|
|
@@ -68,6 +68,7 @@ collect-bounds = "topo_map_processor.tools.collect_bounds:cli"
|
|
|
68
68
|
retile = "topo_map_processor.tools.retile:cli"
|
|
69
69
|
tile = "topo_map_processor.tools.tile:cli"
|
|
70
70
|
retile-e2e = "topo_map_processor.tools.retile_e2e:cli"
|
|
71
|
+
create-force-redo-bounds = "topo_map_processor.tools.create_force_redo_bounds:cli"
|
|
71
72
|
|
|
72
73
|
[build-system]
|
|
73
74
|
requires = [
|
|
@@ -28,7 +28,7 @@ version_tuple: VERSION_TUPLE
|
|
|
28
28
|
commit_id: COMMIT_ID
|
|
29
29
|
__commit_id__: COMMIT_ID
|
|
30
30
|
|
|
31
|
-
__version__ = version = '0.1.
|
|
32
|
-
__version_tuple__ = version_tuple = (0, 1,
|
|
31
|
+
__version__ = version = '0.1.17'
|
|
32
|
+
__version_tuple__ = version_tuple = (0, 1, 17)
|
|
33
33
|
|
|
34
34
|
__commit_id__ = commit_id = None
|
|
@@ -4,6 +4,7 @@ import time
|
|
|
4
4
|
import json
|
|
5
5
|
import pickle
|
|
6
6
|
import shutil
|
|
7
|
+
import hashlib
|
|
7
8
|
import subprocess
|
|
8
9
|
|
|
9
10
|
from pathlib import Path
|
|
@@ -81,6 +82,7 @@ class TopoMapProcessor:
|
|
|
81
82
|
self.small_img = None
|
|
82
83
|
self.mapbox_corners = None
|
|
83
84
|
self.rotation_reversal_params = None
|
|
85
|
+
self.digest = None
|
|
84
86
|
|
|
85
87
|
self.extents = extra.get('extents', None)
|
|
86
88
|
self.pixel_cutlines = extra.get('pixel_cutlines', [])
|
|
@@ -106,6 +108,7 @@ class TopoMapProcessor:
|
|
|
106
108
|
self.use_bbox_area = extra.get('use_bbox_area', True)
|
|
107
109
|
self.shrunk_map_area_corners = extra.get('shrunk_map_area_corners', None)
|
|
108
110
|
self.poly_approx_factor = extra.get('poly_approx_factor', 0.001)
|
|
111
|
+
self.map_area_ratio_thresh = extra.get('map_area_ratio_thresh', 0.5)
|
|
109
112
|
|
|
110
113
|
# corners related
|
|
111
114
|
self.corner_ratio = extra.get('corner_ratio', 400.0 / 9000.0)
|
|
@@ -132,6 +135,7 @@ class TopoMapProcessor:
|
|
|
132
135
|
self.warp_jpeg_export_quality = extra.get('warp_jpeg_export_quality', 75)
|
|
133
136
|
self.warp_output_height = extra.get('warp_output_height', 6500)
|
|
134
137
|
|
|
138
|
+
|
|
135
139
|
self.color_map = {
|
|
136
140
|
'black': ((0, 0, 0), (179, 255, 130)),
|
|
137
141
|
'greyish': ((0, 0, 50), (179, 150, 192)),
|
|
@@ -484,6 +488,10 @@ class TopoMapProcessor:
|
|
|
484
488
|
ls = LineString(line)
|
|
485
489
|
line_poly = ls.buffer(line_buf, resolution=1, cap_style=CAP_STYLE.flat).intersection(limits)
|
|
486
490
|
blur_poly = ls.buffer(blur_buf, resolution=1, cap_style=CAP_STYLE.flat).intersection(limits)
|
|
491
|
+
print(f'removing line {line} with line_buf {line_buf}, blur_buf {blur_buf}, blur_kern {blur_kern}, blur_repeat {blur_repeat}')
|
|
492
|
+
if blur_poly.is_empty:
|
|
493
|
+
print('blur poly empty, nothing to do')
|
|
494
|
+
return
|
|
487
495
|
bb = blur_poly.bounds
|
|
488
496
|
bb = [ round(x) for x in bb ]
|
|
489
497
|
# restrict to a small img strip to make things less costly
|
|
@@ -810,7 +818,7 @@ class TopoMapProcessor:
|
|
|
810
818
|
|
|
811
819
|
h, w = img.shape[:2]
|
|
812
820
|
total_area = w * h
|
|
813
|
-
if
|
|
821
|
+
if map_area / total_area < self.map_area_ratio_thresh:
|
|
814
822
|
raise Exception(f'map area less than expected, {map_area=}, {total_area=}')
|
|
815
823
|
|
|
816
824
|
self.show_contours(img_mask, [map_contour])
|
|
@@ -1088,7 +1096,8 @@ class TopoMapProcessor:
|
|
|
1088
1096
|
if remove_text:
|
|
1089
1097
|
self.remove_text(img_mask)
|
|
1090
1098
|
|
|
1091
|
-
|
|
1099
|
+
if remove_corner_edges_ratio is not None:
|
|
1100
|
+
self.remove_corner_edges(img_mask, direction, remove_corner_edges_ratio)
|
|
1092
1101
|
|
|
1093
1102
|
h, w = img_mask.shape[:2]
|
|
1094
1103
|
self.show_image(img_mask)
|
|
@@ -1166,7 +1175,8 @@ class TopoMapProcessor:
|
|
|
1166
1175
|
|
|
1167
1176
|
anchor_corner = (ax, ay)
|
|
1168
1177
|
|
|
1169
|
-
|
|
1178
|
+
if remove_corner_edges_ratio is not None:
|
|
1179
|
+
self.remove_corner_edges(img_mask, direction, remove_corner_edges_ratio)
|
|
1170
1180
|
|
|
1171
1181
|
frame_contour = self.get_biggest_contour(img_mask, corner_erode, True, max_corner_contour_area_ratio)
|
|
1172
1182
|
|
|
@@ -1230,7 +1240,8 @@ class TopoMapProcessor:
|
|
|
1230
1240
|
|
|
1231
1241
|
img_c_mask = self.get_color_mask(img, corner_contour_color)
|
|
1232
1242
|
self.remove_text(img_c_mask)
|
|
1233
|
-
|
|
1243
|
+
if remove_corner_edges_ratio is not None:
|
|
1244
|
+
self.remove_corner_edges(img_c_mask, direction, remove_corner_edges_ratio)
|
|
1234
1245
|
frame_contour = self.get_biggest_contour(img_c_mask, self.corner_erode, True, max_corner_contour_area_ratio)
|
|
1235
1246
|
|
|
1236
1247
|
frame_contour_area = self.get_bbox_area_simple(frame_contour)
|
|
@@ -1250,6 +1261,7 @@ class TopoMapProcessor:
|
|
|
1250
1261
|
fx + fw * ( 1 if direction[0] < 0 else 0),
|
|
1251
1262
|
fy + fh * ( 1 if direction[1] < 0 else 0),
|
|
1252
1263
|
]
|
|
1264
|
+
|
|
1253
1265
|
frame_diag_len = self.get_distance((0,0), (fh,fw))
|
|
1254
1266
|
self.show_points([frame_anchor_point], img_c_mask, [0,0,255])
|
|
1255
1267
|
|
|
@@ -1294,10 +1306,24 @@ class TopoMapProcessor:
|
|
|
1294
1306
|
map_poly_points = self.reorder_poly_points(map_poly_points)
|
|
1295
1307
|
print(f'{map_poly_points=}')
|
|
1296
1308
|
|
|
1309
|
+
all_corner_overrides_given = all([ c is not None for c in corner_overrides ])
|
|
1310
|
+
if all_corner_overrides_given:
|
|
1311
|
+
return corner_overrides
|
|
1312
|
+
|
|
1313
|
+
some_corner_overrides_given = any([ c is not None for c in corner_overrides ])
|
|
1314
|
+
if some_corner_overrides_given and len(corner_overrides) != len(map_poly_points):
|
|
1315
|
+
raise ValueError("If some corner overrides are given, either all must be given or the number of overrides must match the number of polygon points.")
|
|
1316
|
+
|
|
1297
1317
|
#num_corners = len(map_poly_points)
|
|
1298
1318
|
box = LinearRing(map_poly_points + [map_poly_points[0]])
|
|
1299
1319
|
buffered_poly = box.buffer(-cw/2, single_sided=True, join_style=JOIN_STYLE.mitre)
|
|
1300
|
-
|
|
1320
|
+
|
|
1321
|
+
# TODO: this is a hack.. understand why this happens and fix it properly
|
|
1322
|
+
if len(buffered_poly.interiors) == 0:
|
|
1323
|
+
inner_ring = buffered_poly.exterior
|
|
1324
|
+
else:
|
|
1325
|
+
inner_ring = buffered_poly.interiors[0]
|
|
1326
|
+
|
|
1301
1327
|
corner_centers = list(inner_ring.coords)
|
|
1302
1328
|
corner_centers.reverse()
|
|
1303
1329
|
print(f'{corner_centers=}')
|
|
@@ -1390,7 +1416,7 @@ class TopoMapProcessor:
|
|
|
1390
1416
|
corner_overrides = [ (c[0] - map_bbox_scaled[0], c[1] - map_bbox_scaled[1]) if c is not None else None for c in corner_overrides_full ]
|
|
1391
1417
|
map_poly_points_scaled = [ (p[0] - map_bbox_scaled[0], p[1] - map_bbox_scaled[1]) for p in map_poly_points_scaled ]
|
|
1392
1418
|
|
|
1393
|
-
if
|
|
1419
|
+
if len(corner_overrides) == 4:
|
|
1394
1420
|
corners = self.locate_corners(map_img, corner_overrides)
|
|
1395
1421
|
else:
|
|
1396
1422
|
corners = self.locate_corners_generic(map_img, map_poly_points_scaled, corner_overrides)
|
|
@@ -1610,6 +1636,21 @@ class TopoMapProcessor:
|
|
|
1610
1636
|
translate_cmd = f'gdal_translate {creation_options} {perf_options} {gcp_str} -a_srs "{crs_proj}" -of GTiff {str(from_file)} {str(georef_file)}'
|
|
1611
1637
|
self.run_external(translate_cmd)
|
|
1612
1638
|
|
|
1639
|
+
def get_digest(self):
|
|
1640
|
+
if self.digest is not None:
|
|
1641
|
+
return self.digest
|
|
1642
|
+
|
|
1643
|
+
hasher = hashlib.sha256()
|
|
1644
|
+
export_file = self.get_export_file()
|
|
1645
|
+
with open(export_file, 'rb') as f:
|
|
1646
|
+
while True:
|
|
1647
|
+
data = f.read(65536)
|
|
1648
|
+
if not data:
|
|
1649
|
+
break
|
|
1650
|
+
hasher.update(data)
|
|
1651
|
+
self.digest = hasher.hexdigest()
|
|
1652
|
+
return self.digest
|
|
1653
|
+
|
|
1613
1654
|
def get_cutline_props(self):
|
|
1614
1655
|
crs_proj = self.get_crs_proj()
|
|
1615
1656
|
|
|
@@ -1687,7 +1728,7 @@ class TopoMapProcessor:
|
|
|
1687
1728
|
workdir = self.get_workdir()
|
|
1688
1729
|
rotated_info_file = workdir.joinpath('rotated_info.txt')
|
|
1689
1730
|
if not rotated_info_file.exists():
|
|
1690
|
-
|
|
1731
|
+
return RotationReversalParams(False, 0.0, None, None)
|
|
1691
1732
|
|
|
1692
1733
|
parts = rotated_info_file.read_text().strip().split(',')
|
|
1693
1734
|
angle = float(parts[0])
|
|
@@ -1813,6 +1854,32 @@ class TopoMapProcessor:
|
|
|
1813
1854
|
|
|
1814
1855
|
self.run_external(f'ogr2ogr -t_srs EPSG:4326 -s_srs "{crs_proj}" -f GeoJSONSeq {str(bounds_file)} {cutline_file}')
|
|
1815
1856
|
|
|
1857
|
+
def add_digest_to_bounds_file(self):
|
|
1858
|
+
bounds_dir = self.get_bounds_dir()
|
|
1859
|
+
|
|
1860
|
+
bounds_file = bounds_dir.joinpath(f'{self.get_id()}.geojsonl')
|
|
1861
|
+
if not bounds_file.exists():
|
|
1862
|
+
print(f'{bounds_file} does not exist.. cannot add digest')
|
|
1863
|
+
return
|
|
1864
|
+
|
|
1865
|
+
digest = self.get_digest()
|
|
1866
|
+
|
|
1867
|
+
with open(bounds_file, 'r') as f:
|
|
1868
|
+
lines = f.readlines()
|
|
1869
|
+
|
|
1870
|
+
if len(lines) != 1:
|
|
1871
|
+
print(f'expected 1 line in {bounds_file}, got {len(lines)}')
|
|
1872
|
+
return
|
|
1873
|
+
|
|
1874
|
+
feature = json.loads(lines[0])
|
|
1875
|
+
if 'properties' not in feature:
|
|
1876
|
+
feature['properties'] = {}
|
|
1877
|
+
|
|
1878
|
+
feature['properties']['digest'] = digest
|
|
1879
|
+
|
|
1880
|
+
with open(bounds_file, 'w') as f:
|
|
1881
|
+
f.write(json.dumps(feature) + '\n')
|
|
1882
|
+
|
|
1816
1883
|
def warp(self):
|
|
1817
1884
|
workdir = self.get_workdir()
|
|
1818
1885
|
|
|
@@ -1851,6 +1918,9 @@ class TopoMapProcessor:
|
|
|
1851
1918
|
|
|
1852
1919
|
self.export_gtiff(str(final_file), str(export_file), self.jpeg_export_quality)
|
|
1853
1920
|
|
|
1921
|
+
self.add_digest_to_bounds_file()
|
|
1922
|
+
|
|
1923
|
+
|
|
1854
1924
|
def remove_insets(self):
|
|
1855
1925
|
if self.inset_pixel_cutlines is None or len(self.inset_pixel_cutlines) == 0:
|
|
1856
1926
|
return
|
{topo_map_processor-0.1.16 → topo_map_processor-0.1.17}/topo_map_processor/tools/collect_bounds.py
RENAMED
|
@@ -5,23 +5,32 @@ from pathlib import Path
|
|
|
5
5
|
|
|
6
6
|
def cli():
|
|
7
7
|
parser = argparse.ArgumentParser(description='Collect GeoJSONL files into a single GeoJSON file.')
|
|
8
|
-
parser.add_argument('--bounds-dir', required=True, help='Directory containing GeoJSONL files')
|
|
9
|
-
parser.add_argument('--output-file', required=True, help='Output GeoJSON file path')
|
|
10
|
-
parser.add_argument('
|
|
8
|
+
parser.add_argument('-b', '--bounds-dir', required=True, help='Directory containing GeoJSONL files')
|
|
9
|
+
parser.add_argument('-o', '--output-file', required=True, help='Output GeoJSON file path')
|
|
10
|
+
parser.add_argument('-u', '--update', action='store_true', help='Update the output file in place')
|
|
11
|
+
parser.add_argument('-d', '--delete', nargs='+', help='List of ids to delete from the output file (only in update mode)')
|
|
11
12
|
|
|
12
13
|
args = parser.parse_args()
|
|
13
14
|
|
|
15
|
+
if args.delete and not args.update:
|
|
16
|
+
raise parser.error("--delete can only be used with --update")
|
|
17
|
+
|
|
14
18
|
feat_map = {}
|
|
15
|
-
if args.
|
|
16
|
-
|
|
17
|
-
if not
|
|
18
|
-
raise FileNotFoundError(f"
|
|
19
|
+
if args.update:
|
|
20
|
+
output_file = Path(args.output_file)
|
|
21
|
+
if not output_file.exists():
|
|
22
|
+
raise FileNotFoundError(f"Output file does not exist for updating: {output_file}")
|
|
19
23
|
|
|
20
|
-
existing_data = json.loads(
|
|
24
|
+
existing_data = json.loads(output_file.read_text())
|
|
21
25
|
for feature in existing_data.get('features', []):
|
|
22
26
|
if 'properties' in feature and 'id' in feature['properties']:
|
|
23
27
|
sheet_name = feature['properties']['id']
|
|
24
28
|
feat_map[sheet_name] = feature
|
|
29
|
+
|
|
30
|
+
if args.delete:
|
|
31
|
+
for sheet_id in args.delete:
|
|
32
|
+
if sheet_id in feat_map:
|
|
33
|
+
del feat_map[sheet_id]
|
|
25
34
|
|
|
26
35
|
bounds_dir = Path(args.bounds_dir)
|
|
27
36
|
|
|
@@ -0,0 +1,100 @@
|
|
|
1
|
+
import argparse
|
|
2
|
+
import json
|
|
3
|
+
import sys
|
|
4
|
+
from pathlib import Path
|
|
5
|
+
|
|
6
|
+
def get_sheet_map(bounds_file):
|
|
7
|
+
"""Reads a bounds file and returns a map of sheet ID to feature."""
|
|
8
|
+
with open(bounds_file, 'r') as f:
|
|
9
|
+
data = json.load(f)
|
|
10
|
+
|
|
11
|
+
sheet_map = {}
|
|
12
|
+
for feature in data.get('features', []):
|
|
13
|
+
if 'properties' in feature and 'id' in feature['properties']:
|
|
14
|
+
sheet_id = feature['properties']['id']
|
|
15
|
+
sheet_map[sheet_id] = feature
|
|
16
|
+
return sheet_map
|
|
17
|
+
|
|
18
|
+
def main(argv):
|
|
19
|
+
parser = argparse.ArgumentParser(description='Create a force redo bounds file by comparing old and new bounds.')
|
|
20
|
+
parser.add_argument('--old-bounds-file', required=True, help='Path to the old GeoJSON bounds file.')
|
|
21
|
+
parser.add_argument('--new-bounds-file', required=True, help='Path to the new GeoJSON bounds file.')
|
|
22
|
+
parser.add_argument('--output-file', required=True, help='Path to write the output GeoJSON file with force redo bounds.')
|
|
23
|
+
|
|
24
|
+
args = parser.parse_args(argv)
|
|
25
|
+
|
|
26
|
+
old_sheets = get_sheet_map(args.old_bounds_file)
|
|
27
|
+
new_sheets = get_sheet_map(args.new_bounds_file)
|
|
28
|
+
|
|
29
|
+
old_ids = set(old_sheets.keys())
|
|
30
|
+
new_ids = set(new_sheets.keys())
|
|
31
|
+
|
|
32
|
+
added_ids = new_ids - old_ids
|
|
33
|
+
deleted_ids = old_ids - new_ids
|
|
34
|
+
common_ids = old_ids.intersection(new_ids)
|
|
35
|
+
|
|
36
|
+
output_features = []
|
|
37
|
+
|
|
38
|
+
# Added sheets
|
|
39
|
+
for sheet_id in added_ids:
|
|
40
|
+
feature = new_sheets[sheet_id]
|
|
41
|
+
output_features.append({
|
|
42
|
+
"type": "Feature",
|
|
43
|
+
"geometry": feature['geometry'],
|
|
44
|
+
"properties": { "reason": f"Sheet {sheet_id} added" }
|
|
45
|
+
})
|
|
46
|
+
|
|
47
|
+
# Deleted sheets
|
|
48
|
+
for sheet_id in deleted_ids:
|
|
49
|
+
feature = old_sheets[sheet_id]
|
|
50
|
+
output_features.append({
|
|
51
|
+
"type": "Feature",
|
|
52
|
+
"geometry": feature['geometry'],
|
|
53
|
+
"properties": { "reason": f"Sheet {sheet_id} deleted" }
|
|
54
|
+
})
|
|
55
|
+
|
|
56
|
+
# Common sheets (check for modifications)
|
|
57
|
+
for sheet_id in common_ids:
|
|
58
|
+
old_feature = old_sheets[sheet_id]
|
|
59
|
+
new_feature = new_sheets[sheet_id]
|
|
60
|
+
old_geom = old_feature.get('geometry')
|
|
61
|
+
new_geom = new_feature.get('geometry')
|
|
62
|
+
geom_changed = json.dumps(old_geom, sort_keys=True) != json.dumps(new_geom, sort_keys=True)
|
|
63
|
+
old_digest = old_feature.get('properties', {}).get('digest')
|
|
64
|
+
new_digest = new_feature.get('properties', {}).get('digest')
|
|
65
|
+
digest_changed = old_digest != new_digest
|
|
66
|
+
if geom_changed:
|
|
67
|
+
output_features.append({
|
|
68
|
+
"type": "Feature",
|
|
69
|
+
"geometry": old_geom,
|
|
70
|
+
"properties": { "reason": f"Sheet {sheet_id} geometry changed (old)" }
|
|
71
|
+
})
|
|
72
|
+
output_features.append({
|
|
73
|
+
"type": "Feature",
|
|
74
|
+
"geometry": new_geom,
|
|
75
|
+
"properties": { "reason": f"Sheet {sheet_id} geometry changed (new)" }
|
|
76
|
+
})
|
|
77
|
+
elif digest_changed:
|
|
78
|
+
output_features.append({
|
|
79
|
+
"type": "Feature",
|
|
80
|
+
"geometry": new_geom,
|
|
81
|
+
"properties": { "reason": f"Sheet {sheet_id} digest changed" }
|
|
82
|
+
})
|
|
83
|
+
|
|
84
|
+
with open(args.output_file, 'w') as f:
|
|
85
|
+
f.write('{ "type": "FeatureCollection", "features": [\n')
|
|
86
|
+
for i, feature in enumerate(output_features):
|
|
87
|
+
line = json.dumps(feature)
|
|
88
|
+
if i < len(output_features) - 1:
|
|
89
|
+
line += ','
|
|
90
|
+
line += '\n'
|
|
91
|
+
f.write(line)
|
|
92
|
+
f.write(']}\n')
|
|
93
|
+
|
|
94
|
+
print(f"Created force redo bounds file at {args.output_file} with {len(output_features)} features.")
|
|
95
|
+
|
|
96
|
+
def cli():
|
|
97
|
+
main(sys.argv[1:])
|
|
98
|
+
|
|
99
|
+
if __name__ == "__main__":
|
|
100
|
+
cli()
|
|
@@ -364,8 +364,10 @@ def get_base_tile_sheet_mappings(sheets_to_box, base_zoom):
|
|
|
364
364
|
|
|
365
365
|
def assess_sheet_requirements(retile_list_file, bounds_file, force_redo_bounds_file, max_zoom):
|
|
366
366
|
|
|
367
|
-
retile_sheets =
|
|
368
|
-
|
|
367
|
+
retile_sheets = set()
|
|
368
|
+
if retile_list_file:
|
|
369
|
+
retile_sheets = retile_list_file.read_text().split('\n')
|
|
370
|
+
retile_sheets = set([ r.strip().replace('.tif', '') for r in retile_sheets if r.strip() != '' ])
|
|
369
371
|
|
|
370
372
|
print('getting base tiles to sheet mapping')
|
|
371
373
|
sheets_to_box = get_sheet_data(bounds_file)
|
|
@@ -414,7 +416,7 @@ def create_dummy_sheets(dummy_bounds_file, tiffs_dir):
|
|
|
414
416
|
def retile_main(args):
|
|
415
417
|
|
|
416
418
|
parser = argparse.ArgumentParser()
|
|
417
|
-
parser.add_argument('--retile-list-file', required=
|
|
419
|
+
parser.add_argument('--retile-list-file', required=False, default=None, help='File containing list of sheets to retile')
|
|
418
420
|
parser.add_argument('--bounds-file', required=True, help='Geojson file containing list of available sheets and their georaphic bounds')
|
|
419
421
|
parser.add_argument('--force-redo-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')
|
|
420
422
|
parser.add_argument('--max-zoom', type=int, help='Maximum zoom level to create tiles for, needed only when --from-source is not provided')
|
|
@@ -428,8 +430,11 @@ def retile_main(args):
|
|
|
428
430
|
|
|
429
431
|
args = parser.parse_args(args)
|
|
430
432
|
|
|
431
|
-
retile_list_file
|
|
432
|
-
|
|
433
|
+
if not args.retile_list_file and not args.force_redo_bounds_file:
|
|
434
|
+
parser.error('At least one of --retile-list-file or --force-redo-bounds-file must be provided.')
|
|
435
|
+
|
|
436
|
+
retile_list_file = Path(args.retile_list_file) if args.retile_list_file else None
|
|
437
|
+
if retile_list_file and not retile_list_file.exists():
|
|
433
438
|
parser.error(f'Retile list file {args.retile_list_file} does not exist')
|
|
434
439
|
|
|
435
440
|
bounds_file = Path(args.bounds_file)
|
{topo_map_processor-0.1.16 → topo_map_processor-0.1.17}/topo_map_processor/tools/retile_e2e.py
RENAMED
|
@@ -1,7 +1,6 @@
|
|
|
1
|
-
|
|
2
1
|
import argparse
|
|
3
|
-
import csv
|
|
4
2
|
import glob
|
|
3
|
+
import json
|
|
5
4
|
import shutil
|
|
6
5
|
import subprocess
|
|
7
6
|
import sys
|
|
@@ -11,6 +10,7 @@ from multiprocessing import set_start_method
|
|
|
11
10
|
from pmtiles_mosaic.partition import partition_main
|
|
12
11
|
|
|
13
12
|
from .retile import retile_main
|
|
13
|
+
from .create_force_redo_bounds import main as create_force_redo_bounds_main
|
|
14
14
|
|
|
15
15
|
|
|
16
16
|
def run_command(cmd, check=True, cwd=None):
|
|
@@ -50,7 +50,7 @@ def cli():
|
|
|
50
50
|
parser.add_argument("-p", "--pmtiles-release", required=True, help="PMTiles release tag")
|
|
51
51
|
parser.add_argument("-g", "--gtiffs-release", required=True, help="GeoTIFFs release tag")
|
|
52
52
|
parser.add_argument("-x", "--pmtiles-prefix", required=True, help="Prefix for PMTiles files")
|
|
53
|
-
parser.add_argument("
|
|
53
|
+
parser.add_argument("--bounds-file-tiled", required=True, help="Name of the bounds file in the pmtiles release (the old bounds file)")
|
|
54
54
|
args = parser.parse_args()
|
|
55
55
|
|
|
56
56
|
# Define paths and filenames
|
|
@@ -59,7 +59,10 @@ def cli():
|
|
|
59
59
|
tiffs_dir = Path("staging/gtiffs/")
|
|
60
60
|
from_pmtiles_dir = Path("staging/pmtiles")
|
|
61
61
|
to_pmtiles_dir = Path("export/pmtiles")
|
|
62
|
-
|
|
62
|
+
|
|
63
|
+
old_bounds_file = Path("old_bounds.geojson")
|
|
64
|
+
new_bounds_file = Path("new_bounds.geojson")
|
|
65
|
+
force_redo_bounds_file = Path("force_redo_bounds.geojson")
|
|
63
66
|
|
|
64
67
|
from_pmtiles_prefix = from_pmtiles_dir / args.pmtiles_prefix
|
|
65
68
|
to_pmtiles_prefix = to_pmtiles_dir / args.pmtiles_prefix
|
|
@@ -68,90 +71,71 @@ def cli():
|
|
|
68
71
|
for d in [tiles_dir, tiffs_dir, from_pmtiles_dir, to_pmtiles_dir]:
|
|
69
72
|
d.mkdir(parents=True, exist_ok=True)
|
|
70
73
|
|
|
71
|
-
# Download
|
|
72
|
-
print("Downloading
|
|
73
|
-
run_command(["gh", "release", "download", args.gtiffs_release, "-p", "
|
|
74
|
-
run_command(["gh", "release", "download", args.pmtiles_release, "-p", args.listing_files_tiled, "--clobber", "-O", "listing_files_tiled.csv"])
|
|
75
|
-
|
|
76
|
-
print("Download force redo bounds")
|
|
77
|
-
force_redo_bounds_file = Path("force_redo_bounds.geojson")
|
|
78
|
-
try:
|
|
79
|
-
run_command(["gh", "release", "download", args.pmtiles_release, "-p", f"{force_redo_bounds_file}", "--clobber"])
|
|
80
|
-
print("Force redo bounds file found and downloaded.")
|
|
81
|
-
except subprocess.CalledProcessError:
|
|
82
|
-
print("No force redo bounds file found; proceeding without it.")
|
|
83
|
-
force_redo_bounds_file = None
|
|
84
|
-
|
|
85
|
-
# Determine sheets to retile
|
|
86
|
-
print("Determining sheets to retile...")
|
|
87
|
-
with open("listing_files.csv") as f:
|
|
88
|
-
gtiffs_sheets = {row['name'] for row in csv.DictReader(f)}
|
|
89
|
-
with open("listing_files_tiled.csv") as f:
|
|
90
|
-
pmtiles_sheets = {row['name'] for row in csv.DictReader(f)}
|
|
91
|
-
|
|
92
|
-
sheets_to_retile = sorted(list(gtiffs_sheets - pmtiles_sheets))
|
|
74
|
+
# Download bounds files
|
|
75
|
+
print("Downloading new bounds file from gtiffs release...")
|
|
76
|
+
run_command(["gh", "release", "download", args.gtiffs_release, "-p", "bounds.geojson", "--clobber", "-O", str(new_bounds_file)])
|
|
93
77
|
|
|
94
|
-
|
|
95
|
-
|
|
96
|
-
|
|
97
|
-
|
|
98
|
-
print(
|
|
99
|
-
|
|
78
|
+
print("Downloading old bounds file from pmtiles release...")
|
|
79
|
+
run_command(["gh", "release", "download", args.pmtiles_release, "-p", args.bounds_file_tiled, "--clobber", "-O", str(old_bounds_file)])
|
|
80
|
+
|
|
81
|
+
# Create force redo bounds file
|
|
82
|
+
print("Creating force redo bounds file...")
|
|
83
|
+
create_force_redo_bounds_main([
|
|
84
|
+
"--old-bounds-file", str(old_bounds_file),
|
|
85
|
+
"--new-bounds-file", str(new_bounds_file),
|
|
86
|
+
"--output-file", str(force_redo_bounds_file)
|
|
87
|
+
])
|
|
100
88
|
|
|
101
|
-
if
|
|
102
|
-
|
|
103
|
-
|
|
104
|
-
|
|
89
|
+
# Check if there are any changes
|
|
90
|
+
with open(force_redo_bounds_file) as f:
|
|
91
|
+
force_redo_data = json.load(f)
|
|
92
|
+
|
|
93
|
+
if not force_redo_data.get("features"):
|
|
94
|
+
print("No changes detected between bounds files. Exiting.")
|
|
105
95
|
sys.exit(0)
|
|
106
96
|
|
|
107
|
-
# Download
|
|
108
|
-
print("Downloading bounds file...")
|
|
109
|
-
run_command(["gh", "release", "download", args.gtiffs_release, "-p", "bounds.geojson"])
|
|
97
|
+
# Download original PMTiles
|
|
110
98
|
print("Getting original PMTiles files...")
|
|
111
99
|
run_command(["gh", "release", "download", args.pmtiles_release, "-D", str(from_pmtiles_dir), "-p", f"{args.pmtiles_prefix}*"])
|
|
112
100
|
|
|
113
|
-
extra_bounds_args = []
|
|
114
|
-
if force_redo_bounds_file:
|
|
115
|
-
extra_bounds_args = ["--force-redo-bounds-file", str(force_redo_bounds_file)]
|
|
116
101
|
# Get list of sheets to pull
|
|
117
102
|
print("Getting list of sheets to pull...")
|
|
118
103
|
retile_main([
|
|
119
|
-
"--
|
|
120
|
-
"--bounds-file",
|
|
104
|
+
"--bounds-file", str(new_bounds_file),
|
|
105
|
+
"--force-redo-bounds-file", str(force_redo_bounds_file),
|
|
121
106
|
"--sheets-to-pull-list-outfile", str(sheets_to_pull_list_outfile),
|
|
122
107
|
"--from-source", f"{from_pmtiles_prefix}*.pmtiles",
|
|
123
|
-
]
|
|
108
|
+
])
|
|
124
109
|
|
|
125
110
|
print("Sheets to pull:")
|
|
126
111
|
print(sheets_to_pull_list_outfile.read_text())
|
|
127
112
|
|
|
128
113
|
# Download TIFFs
|
|
129
114
|
print("Downloading TIFFs...")
|
|
130
|
-
with open("listing_files.csv") as f:
|
|
131
|
-
url_map = {row[0]: row[2] for row in csv.reader(f)}
|
|
132
|
-
|
|
133
115
|
with open(sheets_to_pull_list_outfile) as f:
|
|
134
116
|
for line in f:
|
|
135
117
|
fname = line.strip()
|
|
136
|
-
if fname
|
|
137
|
-
url = url_map[fname]
|
|
118
|
+
if fname:
|
|
138
119
|
print(f"Pulling {fname}")
|
|
139
|
-
|
|
120
|
+
try:
|
|
121
|
+
run_command(["gh", "release", "download", args.gtiffs_release, "-p", fname, "-D", str(tiffs_dir), "--clobber"])
|
|
122
|
+
except subprocess.CalledProcessError as e:
|
|
123
|
+
print(f"Failed to download {fname}. It might be a dummy sheet from force redo. Continuing...")
|
|
140
124
|
|
|
141
125
|
sheets_to_pull_list_outfile.unlink()
|
|
142
126
|
|
|
143
127
|
# Retile sheets
|
|
144
128
|
print("Retiling the sheets...")
|
|
145
129
|
retile_main([
|
|
146
|
-
"--
|
|
147
|
-
"--bounds-file",
|
|
130
|
+
"--bounds-file", str(new_bounds_file),
|
|
131
|
+
"--force-redo-bounds-file", str(force_redo_bounds_file),
|
|
148
132
|
"--from-source", f"{from_pmtiles_prefix}*.pmtiles",
|
|
149
133
|
"--tiles-dir", str(tiles_dir),
|
|
150
134
|
"--tiffs-dir", str(tiffs_dir),
|
|
151
|
-
]
|
|
135
|
+
])
|
|
152
136
|
|
|
153
|
-
|
|
154
|
-
|
|
137
|
+
old_bounds_file.unlink()
|
|
138
|
+
force_redo_bounds_file.unlink()
|
|
155
139
|
|
|
156
140
|
# Create new PMTiles files
|
|
157
141
|
print("Creating new pmtiles files...")
|
|
@@ -171,20 +155,14 @@ def cli():
|
|
|
171
155
|
new_pmtiles = glob.glob(f"{to_pmtiles_prefix}*")
|
|
172
156
|
run_command(["gh", "release", "upload", args.pmtiles_release, "--clobber"] + new_pmtiles)
|
|
173
157
|
|
|
174
|
-
# Handle
|
|
175
|
-
|
|
176
|
-
|
|
177
|
-
|
|
158
|
+
# Handle bounds file
|
|
159
|
+
print("Uploading new bounds file to pmtiles release...")
|
|
160
|
+
upload_bounds_file = Path(args.bounds_file_tiled)
|
|
161
|
+
new_bounds_file.rename(upload_bounds_file)
|
|
178
162
|
|
|
179
|
-
|
|
180
|
-
|
|
181
|
-
|
|
182
|
-
|
|
183
|
-
# Handle force redo bounds file
|
|
184
|
-
if force_redo_bounds_file:
|
|
185
|
-
print("Deleting force redo bounds file...")
|
|
186
|
-
run_command(["gh", "release", "delete-asset", args.gtiffs_release, str(force_redo_bounds_file), '-y'])
|
|
187
|
-
force_redo_bounds_file.unlink()
|
|
163
|
+
run_command(["gh", "release", "upload", args.pmtiles_release, str(upload_bounds_file), "--clobber"])
|
|
164
|
+
|
|
165
|
+
upload_bounds_file.unlink()
|
|
188
166
|
|
|
189
167
|
# Cleanup
|
|
190
168
|
print("Cleaning up staging directories...")
|
|
@@ -197,4 +175,4 @@ def cli():
|
|
|
197
175
|
|
|
198
176
|
|
|
199
177
|
if __name__ == "__main__":
|
|
200
|
-
cli()
|
|
178
|
+
cli()
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
{topo_map_processor-0.1.16 → topo_map_processor-0.1.17}/topo_map_processor/tools/__init__.py
RENAMED
|
File without changes
|
|
File without changes
|
|
File without changes
|