topo_map_processor 0.1.7__tar.gz → 0.1.8__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.7 → topo_map_processor-0.1.8}/.gitignore +1 -0
- {topo_map_processor-0.1.7 → topo_map_processor-0.1.8}/PKG-INFO +46 -25
- {topo_map_processor-0.1.7 → topo_map_processor-0.1.8}/README.md +44 -24
- {topo_map_processor-0.1.7 → topo_map_processor-0.1.8}/pyproject.toml +2 -0
- {topo_map_processor-0.1.7 → topo_map_processor-0.1.8}/topo_map_processor/_version.py +2 -2
- {topo_map_processor-0.1.7 → topo_map_processor-0.1.8}/topo_map_processor/bash_scripts/generate_lists.sh +2 -1
- {topo_map_processor-0.1.7 → topo_map_processor-0.1.8}/topo_map_processor/bash_scripts/upload_to_release.sh +2 -1
- topo_map_processor-0.1.8/topo_map_processor/tools/download_mosaic.py +254 -0
- {topo_map_processor-0.1.7 → topo_map_processor-0.1.8}/topo_map_processor/tools/execute_bash.py +4 -1
- topo_map_processor-0.1.8/topo_map_processor/tools/partition.py +433 -0
- topo_map_processor-0.1.8/topo_map_processor/tools/retile.py +474 -0
- {topo_map_processor-0.1.7 → topo_map_processor-0.1.8}/topo_map_processor/tools/tile.py +64 -9
- topo_map_processor-0.1.8/topo_map_processor/tools/tile_sources.py +417 -0
- topo_map_processor-0.1.7/topo_map_processor/tools/partition.py +0 -394
- topo_map_processor-0.1.7/topo_map_processor/tools/retile.py +0 -371
- topo_map_processor-0.1.7/topo_map_processor/tools/tile_sources.py +0 -332
- {topo_map_processor-0.1.7 → topo_map_processor-0.1.8}/LICENSE +0 -0
- {topo_map_processor-0.1.7 → topo_map_processor-0.1.8}/topo_map_processor/__init__.py +0 -0
- {topo_map_processor-0.1.7 → topo_map_processor-0.1.8}/topo_map_processor/bash_scripts/__init__.py +0 -0
- {topo_map_processor-0.1.7 → topo_map_processor-0.1.8}/topo_map_processor/processor.py +0 -0
- {topo_map_processor-0.1.7 → topo_map_processor-0.1.8}/topo_map_processor/tools/__init__.py +0 -0
- {topo_map_processor-0.1.7 → topo_map_processor-0.1.8}/topo_map_processor/tools/collect_bounds.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.8
|
|
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
|
|
@@ -33,6 +33,7 @@ License-File: LICENSE
|
|
|
33
33
|
Requires-Python: >=3.12
|
|
34
34
|
Requires-Dist: mercantile>=1.2.1
|
|
35
35
|
Requires-Dist: pmtiles>=3.4.1
|
|
36
|
+
Requires-Dist: requests>=2.32.4
|
|
36
37
|
Requires-Dist: shapely>=2.1.1
|
|
37
38
|
Provides-Extra: easyocr
|
|
38
39
|
Requires-Dist: easyocr>=1.7.2; extra == 'easyocr'
|
|
@@ -211,9 +212,10 @@ Similar to corner detection, the `locate_grid_lines` method can be implemented u
|
|
|
211
212
|
|
|
212
213
|
The `topo_map_processor.tools.tile_sources` module provides classes for reading tiles from different sources.
|
|
213
214
|
|
|
214
|
-
- `
|
|
215
|
-
- `
|
|
216
|
-
- `
|
|
215
|
+
- `DiskTilesSource`: Reads tiles from a directory on the local disk.
|
|
216
|
+
- `MBTilesSource`: Reads tiles from an MBTiles file.
|
|
217
|
+
- `PMTilesSource`: Reads tiles from a PMTiles file.
|
|
218
|
+
- `StackedTileSource`: Combines multiple tile sources (Disk, MBTiles, PMTiles) into a single logical source, allowing for seamless access across different storage types.
|
|
217
219
|
|
|
218
220
|
### Command-Line Tools
|
|
219
221
|
|
|
@@ -231,24 +233,37 @@ collect-bounds --bounds-dir <directory> --output-file <file> [--preexisting-file
|
|
|
231
233
|
- `--output-file`: Output GeoJSON file path. (Required)
|
|
232
234
|
- `--preexisting-file`: Pre existing GeoJSON file path. (Optional)
|
|
233
235
|
|
|
236
|
+
#### `download-mosaic`
|
|
237
|
+
|
|
238
|
+
Downloads a PMTiles mosaic and converts it to a single MBTiles file. A mosaic is a JSON file that lists multiple PMTiles files.
|
|
239
|
+
|
|
240
|
+
```bash
|
|
241
|
+
download-mosaic --mosaic_url <url> [--output_file <file>] [--request-timeout-secs <seconds>] [--num-http-retries <retries>]
|
|
242
|
+
```
|
|
243
|
+
|
|
244
|
+
- `--mosaic_url`, `-u`: URL of the mosaic JSON file. (Required)
|
|
245
|
+
- `--output_file`, `-o`: Output MBTiles file name. If not specified, it is derived from the mosaic URL. (Optional)
|
|
246
|
+
- `--request-timeout-secs`, `-t`: Timeout for HTTP requests in seconds (default: 60).
|
|
247
|
+
- `--num-http-retries`, `-r`: Number of retries for HTTP requests (default: 3).
|
|
248
|
+
|
|
234
249
|
#### `partition`
|
|
235
250
|
|
|
236
|
-
Partitions a large set of tiles into smaller PMTiles files. This is useful for managing large datasets, for example, to stay within file size limits for services like GitHub Releases.
|
|
251
|
+
Partitions a large set of tiles into smaller PMTiles files. This is useful for managing large datasets, for example, to stay within file size limits for services like GitHub Releases. It creates a mosaic file if the output is partitioned into multiple files.
|
|
237
252
|
|
|
238
253
|
```bash
|
|
239
|
-
partition --
|
|
254
|
+
partition --from-source <source> [--from-source <source> ...] --to-pmtiles <file> [--size-limit <limit>]
|
|
240
255
|
```
|
|
241
256
|
|
|
242
|
-
- `--
|
|
243
|
-
-
|
|
244
|
-
-
|
|
245
|
-
-
|
|
246
|
-
- `--
|
|
247
|
-
- `--
|
|
248
|
-
-
|
|
249
|
-
-
|
|
250
|
-
-
|
|
251
|
-
|
|
257
|
+
- `--from-source`: Path to a source file or directory. Can be repeated. Supported sources:
|
|
258
|
+
- `.mbtiles` file: e.g., `path/to/file.mbtiles`
|
|
259
|
+
- `.pmtiles` file (supports glob patterns): e.g., `path/to/*.pmtiles`
|
|
260
|
+
- Directory containing tiles: e.g., `path/to/tiles_dir`
|
|
261
|
+
- `--to-pmtiles`: Output PMTiles file. The prefix for partitioned files will be derived from this argument.
|
|
262
|
+
- `--size-limit`: Maximum size of each partition. Can be a number in bytes (e.g., `100000000`), or with units (e.g., `100M`, `2G`), or a preset:
|
|
263
|
+
- `github_release`: 2GB limit
|
|
264
|
+
- `github_file`: 100MB limit
|
|
265
|
+
- `cloudflare_object`: 512MB limit
|
|
266
|
+
The overhead (delta) is scaled proportionally based on the `github_release` preset (2GB with 5MB overhead). Defaults to `github_release`.
|
|
252
267
|
|
|
253
268
|
#### `retile`
|
|
254
269
|
|
|
@@ -259,31 +274,37 @@ The tool works in two stages. First, it calculates the full set of sheets that n
|
|
|
259
274
|
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.
|
|
260
275
|
|
|
261
276
|
```bash
|
|
262
|
-
retile --retile-list-file <file> --bounds-file <file> [--max-zoom <zoom>] [--
|
|
277
|
+
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>]
|
|
263
278
|
```
|
|
264
279
|
|
|
265
280
|
- `--retile-list-file`: File containing the list of sheets to retile. (Required)
|
|
266
281
|
- `--bounds-file`: GeoJSON file containing the list of available sheets and their geographic bounds. (Required)
|
|
267
|
-
- `--max-zoom`: Maximum zoom level to create tiles for.
|
|
268
|
-
- `--min-zoom`: Minimum zoom level to create tiles for. (Defaults to the min zoom from the PMTiles source)
|
|
282
|
+
- `--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.
|
|
269
283
|
- `--tiffs-dir`: Directory where the GeoTIFFs are located. (Required if not in pull-list generation mode)
|
|
270
284
|
- `--tiles-dir`: Directory where the tiles will be created. (Required if not in pull-list generation mode)
|
|
271
|
-
- `--from-
|
|
285
|
+
- `--from-source`: Location of the source from which to pull existing tiles. Can be a glob pattern to match a group of pmtiles. Required if not in pull-list generation mode.
|
|
272
286
|
- `--sheets-to-pull-list-outfile`: If provided, the script will only calculate the full list of sheets that need to be processed (including adjacent ones) and write it to this file, then exit.
|
|
273
287
|
- `--num-parallel`: Number of parallel processes to use for tiling (default: number of CPU cores).
|
|
288
|
+
- `--tile-quality`: Quality of compression for webp and jpg (default: 75).
|
|
274
289
|
|
|
275
290
|
#### `tile`
|
|
276
291
|
|
|
277
292
|
Creates web map tiles from a directory of GeoTIFF files. It combines them into a virtual raster (`.vrt`) for efficient processing.
|
|
278
293
|
|
|
279
294
|
```bash
|
|
280
|
-
tile --tiles-dir <dir> --tiffs-dir <dir> --max-zoom <zoom> [--min-zoom <zoom>] [--num-parallel <processes>]
|
|
295
|
+
tile --tiles-dir <dir> --tiffs-dir <dir> --max-zoom <zoom> --name <name> --description <desc> (--attribution <text> | --attribution-file <file>) [--min-zoom <zoom>] [--tile-extension <ext>] [--tile-quality <quality>] [--num-parallel <processes>]
|
|
281
296
|
```
|
|
282
297
|
|
|
283
|
-
-
|
|
284
|
-
-
|
|
285
|
-
-
|
|
286
|
-
-
|
|
298
|
+
- `--tiles-dir`: Directory to store the output tiles. (Required)
|
|
299
|
+
- `--tiffs-dir`: Directory containing the input GeoTIFF files. (Required)
|
|
300
|
+
- `--max-zoom`: Maximum zoom level for tiling. (Required)
|
|
301
|
+
- `--name`: Name of the mosaic. (Required)
|
|
302
|
+
- `--description`: Description of the mosaic. (Required)
|
|
303
|
+
- `--attribution`: Attribution text for the mosaic. Required if `--attribution-file` is not used.
|
|
304
|
+
- `--attribution-file`: File containing attribution text for the mosaic. Required if `--attribution` is not used.
|
|
305
|
+
- `--min-zoom`: Minimum zoom level for tiling (default: 0).
|
|
306
|
+
- `--tile-extension`: Tile file extension (default: webp). Choices: `webp`, `jpg`, `jpeg`, `png`.
|
|
307
|
+
- `--tile-quality`: Compression quality of the tiles for `webp` and `jpg` (default: 75).
|
|
287
308
|
- `--num-parallel`: Number of parallel processes to use for tiling (default: number of CPU cores).
|
|
288
309
|
|
|
289
310
|
### Running Tools Directly with `uvx`
|
|
@@ -163,9 +163,10 @@ Similar to corner detection, the `locate_grid_lines` method can be implemented u
|
|
|
163
163
|
|
|
164
164
|
The `topo_map_processor.tools.tile_sources` module provides classes for reading tiles from different sources.
|
|
165
165
|
|
|
166
|
-
- `
|
|
167
|
-
- `
|
|
168
|
-
- `
|
|
166
|
+
- `DiskTilesSource`: Reads tiles from a directory on the local disk.
|
|
167
|
+
- `MBTilesSource`: Reads tiles from an MBTiles file.
|
|
168
|
+
- `PMTilesSource`: Reads tiles from a PMTiles file.
|
|
169
|
+
- `StackedTileSource`: Combines multiple tile sources (Disk, MBTiles, PMTiles) into a single logical source, allowing for seamless access across different storage types.
|
|
169
170
|
|
|
170
171
|
### Command-Line Tools
|
|
171
172
|
|
|
@@ -183,24 +184,37 @@ collect-bounds --bounds-dir <directory> --output-file <file> [--preexisting-file
|
|
|
183
184
|
- `--output-file`: Output GeoJSON file path. (Required)
|
|
184
185
|
- `--preexisting-file`: Pre existing GeoJSON file path. (Optional)
|
|
185
186
|
|
|
187
|
+
#### `download-mosaic`
|
|
188
|
+
|
|
189
|
+
Downloads a PMTiles mosaic and converts it to a single MBTiles file. A mosaic is a JSON file that lists multiple PMTiles files.
|
|
190
|
+
|
|
191
|
+
```bash
|
|
192
|
+
download-mosaic --mosaic_url <url> [--output_file <file>] [--request-timeout-secs <seconds>] [--num-http-retries <retries>]
|
|
193
|
+
```
|
|
194
|
+
|
|
195
|
+
- `--mosaic_url`, `-u`: URL of the mosaic JSON file. (Required)
|
|
196
|
+
- `--output_file`, `-o`: Output MBTiles file name. If not specified, it is derived from the mosaic URL. (Optional)
|
|
197
|
+
- `--request-timeout-secs`, `-t`: Timeout for HTTP requests in seconds (default: 60).
|
|
198
|
+
- `--num-http-retries`, `-r`: Number of retries for HTTP requests (default: 3).
|
|
199
|
+
|
|
186
200
|
#### `partition`
|
|
187
201
|
|
|
188
|
-
Partitions a large set of tiles into smaller PMTiles files. This is useful for managing large datasets, for example, to stay within file size limits for services like GitHub Releases.
|
|
202
|
+
Partitions a large set of tiles into smaller PMTiles files. This is useful for managing large datasets, for example, to stay within file size limits for services like GitHub Releases. It creates a mosaic file if the output is partitioned into multiple files.
|
|
189
203
|
|
|
190
204
|
```bash
|
|
191
|
-
partition --
|
|
205
|
+
partition --from-source <source> [--from-source <source> ...] --to-pmtiles <file> [--size-limit <limit>]
|
|
192
206
|
```
|
|
193
207
|
|
|
194
|
-
- `--
|
|
195
|
-
-
|
|
196
|
-
-
|
|
197
|
-
-
|
|
198
|
-
- `--
|
|
199
|
-
- `--
|
|
200
|
-
-
|
|
201
|
-
-
|
|
202
|
-
-
|
|
203
|
-
|
|
208
|
+
- `--from-source`: Path to a source file or directory. Can be repeated. Supported sources:
|
|
209
|
+
- `.mbtiles` file: e.g., `path/to/file.mbtiles`
|
|
210
|
+
- `.pmtiles` file (supports glob patterns): e.g., `path/to/*.pmtiles`
|
|
211
|
+
- Directory containing tiles: e.g., `path/to/tiles_dir`
|
|
212
|
+
- `--to-pmtiles`: Output PMTiles file. The prefix for partitioned files will be derived from this argument.
|
|
213
|
+
- `--size-limit`: Maximum size of each partition. Can be a number in bytes (e.g., `100000000`), or with units (e.g., `100M`, `2G`), or a preset:
|
|
214
|
+
- `github_release`: 2GB limit
|
|
215
|
+
- `github_file`: 100MB limit
|
|
216
|
+
- `cloudflare_object`: 512MB limit
|
|
217
|
+
The overhead (delta) is scaled proportionally based on the `github_release` preset (2GB with 5MB overhead). Defaults to `github_release`.
|
|
204
218
|
|
|
205
219
|
#### `retile`
|
|
206
220
|
|
|
@@ -211,31 +225,37 @@ The tool works in two stages. First, it calculates the full set of sheets that n
|
|
|
211
225
|
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.
|
|
212
226
|
|
|
213
227
|
```bash
|
|
214
|
-
retile --retile-list-file <file> --bounds-file <file> [--max-zoom <zoom>] [--
|
|
228
|
+
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>]
|
|
215
229
|
```
|
|
216
230
|
|
|
217
231
|
- `--retile-list-file`: File containing the list of sheets to retile. (Required)
|
|
218
232
|
- `--bounds-file`: GeoJSON file containing the list of available sheets and their geographic bounds. (Required)
|
|
219
|
-
- `--max-zoom`: Maximum zoom level to create tiles for.
|
|
220
|
-
- `--min-zoom`: Minimum zoom level to create tiles for. (Defaults to the min zoom from the PMTiles source)
|
|
233
|
+
- `--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.
|
|
221
234
|
- `--tiffs-dir`: Directory where the GeoTIFFs are located. (Required if not in pull-list generation mode)
|
|
222
235
|
- `--tiles-dir`: Directory where the tiles will be created. (Required if not in pull-list generation mode)
|
|
223
|
-
- `--from-
|
|
236
|
+
- `--from-source`: Location of the source from which to pull existing tiles. Can be a glob pattern to match a group of pmtiles. Required if not in pull-list generation mode.
|
|
224
237
|
- `--sheets-to-pull-list-outfile`: If provided, the script will only calculate the full list of sheets that need to be processed (including adjacent ones) and write it to this file, then exit.
|
|
225
238
|
- `--num-parallel`: Number of parallel processes to use for tiling (default: number of CPU cores).
|
|
239
|
+
- `--tile-quality`: Quality of compression for webp and jpg (default: 75).
|
|
226
240
|
|
|
227
241
|
#### `tile`
|
|
228
242
|
|
|
229
243
|
Creates web map tiles from a directory of GeoTIFF files. It combines them into a virtual raster (`.vrt`) for efficient processing.
|
|
230
244
|
|
|
231
245
|
```bash
|
|
232
|
-
tile --tiles-dir <dir> --tiffs-dir <dir> --max-zoom <zoom> [--min-zoom <zoom>] [--num-parallel <processes>]
|
|
246
|
+
tile --tiles-dir <dir> --tiffs-dir <dir> --max-zoom <zoom> --name <name> --description <desc> (--attribution <text> | --attribution-file <file>) [--min-zoom <zoom>] [--tile-extension <ext>] [--tile-quality <quality>] [--num-parallel <processes>]
|
|
233
247
|
```
|
|
234
248
|
|
|
235
|
-
-
|
|
236
|
-
-
|
|
237
|
-
-
|
|
238
|
-
-
|
|
249
|
+
- `--tiles-dir`: Directory to store the output tiles. (Required)
|
|
250
|
+
- `--tiffs-dir`: Directory containing the input GeoTIFF files. (Required)
|
|
251
|
+
- `--max-zoom`: Maximum zoom level for tiling. (Required)
|
|
252
|
+
- `--name`: Name of the mosaic. (Required)
|
|
253
|
+
- `--description`: Description of the mosaic. (Required)
|
|
254
|
+
- `--attribution`: Attribution text for the mosaic. Required if `--attribution-file` is not used.
|
|
255
|
+
- `--attribution-file`: File containing attribution text for the mosaic. Required if `--attribution` is not used.
|
|
256
|
+
- `--min-zoom`: Minimum zoom level for tiling (default: 0).
|
|
257
|
+
- `--tile-extension`: Tile file extension (default: webp). Choices: `webp`, `jpg`, `jpeg`, `png`.
|
|
258
|
+
- `--tile-quality`: Compression quality of the tiles for `webp` and `jpg` (default: 75).
|
|
239
259
|
- `--num-parallel`: Number of parallel processes to use for tiling (default: number of CPU cores).
|
|
240
260
|
|
|
241
261
|
### Running Tools Directly with `uvx`
|
|
@@ -10,6 +10,7 @@ authors = [
|
|
|
10
10
|
dependencies = [
|
|
11
11
|
"mercantile>=1.2.1",
|
|
12
12
|
"pmtiles>=3.4.1",
|
|
13
|
+
"requests>=2.32.4",
|
|
13
14
|
"shapely>=2.1.1",
|
|
14
15
|
]
|
|
15
16
|
dynamic = [
|
|
@@ -37,6 +38,7 @@ repository = "https://github.com/ramSeraph/topo_map_processor.git"
|
|
|
37
38
|
|
|
38
39
|
[project.scripts]
|
|
39
40
|
collect-bounds = "topo_map_processor.tools.collect_bounds:cli"
|
|
41
|
+
download-mosaic = "topo_map_processor.tools.download_mosaic:cli"
|
|
40
42
|
partition = "topo_map_processor.tools.partition:cli"
|
|
41
43
|
retile = "topo_map_processor.tools.retile:cli"
|
|
42
44
|
tile = "topo_map_processor.tools.tile:cli"
|
|
@@ -1,10 +1,11 @@
|
|
|
1
1
|
#!/bin/bash
|
|
2
2
|
|
|
3
|
+
prog_name=${COMMNAND_NAME:-$(basename "$0")}
|
|
3
4
|
release_base=$1
|
|
4
5
|
ext=$2
|
|
5
6
|
|
|
6
7
|
if [ -z "$release_base" ] || [ -z "$ext" ]; then
|
|
7
|
-
echo "Usage: $
|
|
8
|
+
echo "Usage: $prog_name <release_base> <extension>"
|
|
8
9
|
exit 1
|
|
9
10
|
fi
|
|
10
11
|
|
|
@@ -11,9 +11,10 @@ set -o pipefail
|
|
|
11
11
|
# TAG: The git tag of the release to upload to.
|
|
12
12
|
# FOLDER: The local folder containing the files to upload.
|
|
13
13
|
# OVERWRITE: Optional. Set to 'yes' to allow overwriting existing assets.
|
|
14
|
+
prog_name=${COMMNAND_NAME:-$(basename "$0")}
|
|
14
15
|
|
|
15
16
|
if [ "$#" -lt 3 ] || [ "$#" -gt 4 ]; then
|
|
16
|
-
echo "Usage: $
|
|
17
|
+
echo "Usage: $prog_name <tag> <folder> <extension_without_the_leading_dot> [yes_to_overwrite]"
|
|
17
18
|
exit 1
|
|
18
19
|
fi
|
|
19
20
|
|
|
@@ -0,0 +1,254 @@
|
|
|
1
|
+
#!/usr/bin/env -S uv run
|
|
2
|
+
# /// script
|
|
3
|
+
# requires-python = ">=3.12"
|
|
4
|
+
# dependencies = [
|
|
5
|
+
# "mercantile",
|
|
6
|
+
# "pmtiles",
|
|
7
|
+
# "requests",
|
|
8
|
+
# ]
|
|
9
|
+
# ///
|
|
10
|
+
|
|
11
|
+
import json
|
|
12
|
+
import sqlite3
|
|
13
|
+
|
|
14
|
+
from pathlib import Path, PurePosixPath
|
|
15
|
+
from urllib.parse import urlparse, urljoin, unquote
|
|
16
|
+
|
|
17
|
+
import requests
|
|
18
|
+
from requests.adapters import HTTPAdapter
|
|
19
|
+
from requests.packages.urllib3.util.retry import Retry
|
|
20
|
+
|
|
21
|
+
from pmtiles.reader import Reader, MmapSource, all_tiles
|
|
22
|
+
|
|
23
|
+
# heavily copied from https://github.com/protomaps/PMTiles/blob/main/python/pmtiles/convert.py
|
|
24
|
+
# and https://github.com/mapbox/mbutil/blob/master/mbutil/util.py
|
|
25
|
+
|
|
26
|
+
session = None
|
|
27
|
+
timeout = None
|
|
28
|
+
|
|
29
|
+
def download_file(url, fname):
|
|
30
|
+
global session, timeout
|
|
31
|
+
print(f'downloading {url} to {fname}')
|
|
32
|
+
resp = session.get(url, stream=True, timeout=timeout)
|
|
33
|
+
with open(fname, 'wb') as f:
|
|
34
|
+
for data in resp.iter_content(chunk_size=4096):
|
|
35
|
+
f.write(data)
|
|
36
|
+
|
|
37
|
+
|
|
38
|
+
def get_mosaic(mosaic_file, mosaic_url):
|
|
39
|
+
if not mosaic_file.exists():
|
|
40
|
+
download_file(mosaic_url, mosaic_file)
|
|
41
|
+
|
|
42
|
+
return json.loads(mosaic_file.read_text())
|
|
43
|
+
|
|
44
|
+
|
|
45
|
+
def get_metadata(mosaic_data):
|
|
46
|
+
ch = {}
|
|
47
|
+
|
|
48
|
+
cm = list(mosaic_data.values())[0]['metadata']
|
|
49
|
+
for k, item in mosaic_data.items():
|
|
50
|
+
h = item['header']
|
|
51
|
+
if 'max_zoom' not in ch or ch['max_zoom'] < h['max_zoom']:
|
|
52
|
+
ch['max_zoom'] = h['max_zoom']
|
|
53
|
+
if 'min_zoom' not in ch or ch['min_zoom'] > h['min_zoom']:
|
|
54
|
+
ch['min_zoom'] = h['min_zoom']
|
|
55
|
+
if 'max_lat_e7' not in ch or ch['max_lat_e7'] < h['max_lat_e7']:
|
|
56
|
+
ch['max_lat_e7'] = h['max_lat_e7']
|
|
57
|
+
if 'min_lat_e7' not in ch or ch['min_lat_e7'] > h['min_lat_e7']:
|
|
58
|
+
ch['min_lat_e7'] = h['min_lat_e7']
|
|
59
|
+
if 'max_lon_e7' not in ch or ch['max_lon_e7'] < h['max_lon_e7']:
|
|
60
|
+
ch['max_lon_e7'] = h['max_lon_e7']
|
|
61
|
+
if 'min_lon_e7' not in ch or ch['min_lon_e7'] > h['min_lon_e7']:
|
|
62
|
+
ch['min_lon_e7'] = h['min_lon_e7']
|
|
63
|
+
|
|
64
|
+
cm['maxzoom'] = ch['max_zoom']
|
|
65
|
+
cm['minzoom'] = ch['min_zoom']
|
|
66
|
+
|
|
67
|
+
max_lat = ch['max_lat_e7'] / 10000000
|
|
68
|
+
min_lat = ch['min_lat_e7'] / 10000000
|
|
69
|
+
max_lon = ch['max_lon_e7'] / 10000000
|
|
70
|
+
min_lon = ch['min_lon_e7'] / 10000000
|
|
71
|
+
cm['bounds'] = f"{min_lon},{min_lat},{max_lon},{max_lat}"
|
|
72
|
+
|
|
73
|
+
center_lat = (max_lat + min_lat) / 2
|
|
74
|
+
center_lon = (max_lon + min_lon) / 2
|
|
75
|
+
center_zoom = (ch['max_zoom'] + ch['min_zoom']) // 2
|
|
76
|
+
cm['center'] = f"{center_lon},{center_lat},{center_zoom}"
|
|
77
|
+
|
|
78
|
+
vector_layers = cm.get('vector_layers', [])
|
|
79
|
+
for layer in vector_layers:
|
|
80
|
+
layer['minzoom'] = cm['minzoom']
|
|
81
|
+
layer['maxzoom'] = cm['maxzoom']
|
|
82
|
+
|
|
83
|
+
return cm
|
|
84
|
+
|
|
85
|
+
|
|
86
|
+
def finalize_mbtiles(conn, cursor):
|
|
87
|
+
cursor.execute(
|
|
88
|
+
"CREATE UNIQUE INDEX tile_index on tiles (zoom_level, tile_column, tile_row);"
|
|
89
|
+
)
|
|
90
|
+
conn.commit()
|
|
91
|
+
cursor.execute("""ANALYZE;""")
|
|
92
|
+
|
|
93
|
+
conn.close()
|
|
94
|
+
|
|
95
|
+
|
|
96
|
+
def add_to_mbtiles(pmtiles_fname, cursor, conn):
|
|
97
|
+
print(f'adding {pmtiles_fname} to mbtiles')
|
|
98
|
+
with open(pmtiles_fname, "r+b") as f:
|
|
99
|
+
source = MmapSource(f)
|
|
100
|
+
reader = Reader(source)
|
|
101
|
+
|
|
102
|
+
for zxy, tile_data in all_tiles(reader.get_bytes):
|
|
103
|
+
flipped_y = (1 << zxy[0]) - 1 - zxy[2]
|
|
104
|
+
cursor.execute(
|
|
105
|
+
"INSERT INTO tiles VALUES(?,?,?,?)",
|
|
106
|
+
(zxy[0], zxy[1], flipped_y, tile_data),
|
|
107
|
+
)
|
|
108
|
+
conn.commit()
|
|
109
|
+
|
|
110
|
+
|
|
111
|
+
def optimize_cursor(cursor):
|
|
112
|
+
cursor.execute("""PRAGMA synchronous=0""")
|
|
113
|
+
cursor.execute("""PRAGMA locking_mode=EXCLUSIVE""")
|
|
114
|
+
cursor.execute("""PRAGMA journal_mode=DELETE""")
|
|
115
|
+
|
|
116
|
+
|
|
117
|
+
def initialize_tables(cursor, metadata):
|
|
118
|
+
cursor.execute("CREATE TABLE metadata (name text, value text);")
|
|
119
|
+
cursor.execute(
|
|
120
|
+
"CREATE TABLE tiles (zoom_level integer, tile_column integer, tile_row integer, tile_data blob);"
|
|
121
|
+
)
|
|
122
|
+
|
|
123
|
+
json_metadata = {}
|
|
124
|
+
for k, v in metadata.items():
|
|
125
|
+
if k == "vector_layers":
|
|
126
|
+
json_metadata["vector_layers"] = v
|
|
127
|
+
continue
|
|
128
|
+
elif k == "tilestats":
|
|
129
|
+
json_metadata["tilestats"] = v
|
|
130
|
+
continue
|
|
131
|
+
elif not isinstance(v, str):
|
|
132
|
+
v = json.dumps(v, ensure_ascii=False)
|
|
133
|
+
cursor.execute("INSERT INTO metadata VALUES(?,?)", (k, v))
|
|
134
|
+
|
|
135
|
+
if len(json_metadata) > 0:
|
|
136
|
+
cursor.execute(
|
|
137
|
+
"INSERT INTO metadata VALUES(?,?)",
|
|
138
|
+
("json", json.dumps(json_metadata, ensure_ascii=False)),
|
|
139
|
+
)
|
|
140
|
+
|
|
141
|
+
|
|
142
|
+
|
|
143
|
+
def get_mbtiles_conn(output_file):
|
|
144
|
+
conn = sqlite3.connect(output_file)
|
|
145
|
+
cursor = conn.cursor()
|
|
146
|
+
optimize_cursor(cursor)
|
|
147
|
+
return conn, cursor
|
|
148
|
+
|
|
149
|
+
|
|
150
|
+
def get_pmtiles_url(mosaic_url, k):
|
|
151
|
+
# undo prioir ididocy
|
|
152
|
+
if k.startswith('../') and mosaic_url.startswith('https://github.com/ramSeraph/'):
|
|
153
|
+
k = k[3:]
|
|
154
|
+
return urljoin(mosaic_url, k)
|
|
155
|
+
|
|
156
|
+
|
|
157
|
+
def init_tracker(tracker_file):
|
|
158
|
+
if not tracker_file.exists():
|
|
159
|
+
tracker_file.write_text("")
|
|
160
|
+
|
|
161
|
+
def stage_done(tracker_file, stage):
|
|
162
|
+
txt = tracker_file.read_text()
|
|
163
|
+
|
|
164
|
+
done_stages = txt.split('\n')
|
|
165
|
+
|
|
166
|
+
if stage in done_stages:
|
|
167
|
+
return True
|
|
168
|
+
|
|
169
|
+
return False
|
|
170
|
+
|
|
171
|
+
|
|
172
|
+
def mark_done(tracker_file, stage):
|
|
173
|
+
with open(tracker_file, 'a') as f:
|
|
174
|
+
f.write(stage)
|
|
175
|
+
f.write('\n')
|
|
176
|
+
|
|
177
|
+
def get_filename_from_url(url):
|
|
178
|
+
url_parsed = urlparse(url)
|
|
179
|
+
return unquote(PurePosixPath(url_parsed.path).name)
|
|
180
|
+
|
|
181
|
+
def cli():
|
|
182
|
+
import argparse
|
|
183
|
+
parser = argparse.ArgumentParser(description='Download a mosaic and convert it to MBTiles format.')
|
|
184
|
+
parser.add_argument('--mosaic_url', '-u', required=True, type=str, help='URL of the mosaic JSON file')
|
|
185
|
+
parser.add_argument('--output_file', '-o', type=str, help='Output MBTiles file name, if not specified is derived from the mosaic URL')
|
|
186
|
+
parser.add_argument('--request-timeout-secs', '-t', type=int, default=60, help='Timeout for HTTP requests in seconds')
|
|
187
|
+
parser.add_argument('--num-http-retries', '-r', type=int, default=3, help='Number of retries for HTTP requests')
|
|
188
|
+
args = parser.parse_args()
|
|
189
|
+
|
|
190
|
+
mosaic_url = args.mosaic_url
|
|
191
|
+
|
|
192
|
+
mosaic_fname = get_filename_from_url(mosaic_url)
|
|
193
|
+
|
|
194
|
+
mosaic_file = Path(mosaic_fname)
|
|
195
|
+
mosaic_data = get_mosaic(mosaic_file, mosaic_url)
|
|
196
|
+
metadata = get_metadata(mosaic_data)
|
|
197
|
+
|
|
198
|
+
if args.output_file:
|
|
199
|
+
out_mbtiles_file = Path(args.output_file)
|
|
200
|
+
else:
|
|
201
|
+
if not mosaic_fname.endswith('.mosaic.json'):
|
|
202
|
+
raise ValueError('Output file must end with .mosaic.json, if the output_file is not specified.')
|
|
203
|
+
|
|
204
|
+
out_mbtiles_fname = mosaic_fname[:-len('.mosaic.json')] + '.mbtiles'
|
|
205
|
+
out_mbtiles_file = Path(out_mbtiles_fname)
|
|
206
|
+
|
|
207
|
+
tracker_file = Path('tracker.txt')
|
|
208
|
+
|
|
209
|
+
if out_mbtiles_file.exists() and not tracker_file.exists():
|
|
210
|
+
print(f'Output file {out_mbtiles_file} already exists, and no tracker file found. Exiting to avoid overwriting.')
|
|
211
|
+
return
|
|
212
|
+
|
|
213
|
+
conn, cursor = get_mbtiles_conn(out_mbtiles_file)
|
|
214
|
+
|
|
215
|
+
init_tracker(tracker_file)
|
|
216
|
+
|
|
217
|
+
print(f'Output MBTiles file: {out_mbtiles_file}')
|
|
218
|
+
|
|
219
|
+
if not stage_done(tracker_file, 'table_init'):
|
|
220
|
+
print('Initializing tables...')
|
|
221
|
+
initialize_tables(cursor, metadata)
|
|
222
|
+
mark_done(tracker_file, 'table_init')
|
|
223
|
+
|
|
224
|
+
global session, timeout
|
|
225
|
+
session = requests.session()
|
|
226
|
+
retries = args.num_http_retries
|
|
227
|
+
retry = Retry(
|
|
228
|
+
total=retries,
|
|
229
|
+
read=retries,
|
|
230
|
+
connect=retries,
|
|
231
|
+
)
|
|
232
|
+
session.mount('http://', HTTPAdapter(max_retries=retry))
|
|
233
|
+
session.mount('https://', HTTPAdapter(max_retries=retry))
|
|
234
|
+
timeout = args.request_timeout_secs
|
|
235
|
+
|
|
236
|
+
for k in mosaic_data.keys():
|
|
237
|
+
pmtiles_url = get_pmtiles_url(mosaic_url, k)
|
|
238
|
+
if stage_done(tracker_file, k):
|
|
239
|
+
continue
|
|
240
|
+
|
|
241
|
+
pmtiles_fname = get_filename_from_url(pmtiles_url)
|
|
242
|
+
download_file(pmtiles_url, pmtiles_fname)
|
|
243
|
+
add_to_mbtiles(pmtiles_fname, cursor, conn)
|
|
244
|
+
mark_done(tracker_file, k)
|
|
245
|
+
Path(pmtiles_fname).unlink()
|
|
246
|
+
|
|
247
|
+
finalize_mbtiles(conn, cursor)
|
|
248
|
+
tracker_file.unlink()
|
|
249
|
+
mosaic_file.unlink()
|
|
250
|
+
print('Done!!!')
|
|
251
|
+
|
|
252
|
+
|
|
253
|
+
if __name__ == '__main__':
|
|
254
|
+
cli()
|
{topo_map_processor-0.1.7 → topo_map_processor-0.1.8}/topo_map_processor/tools/execute_bash.py
RENAMED
|
@@ -1,6 +1,7 @@
|
|
|
1
|
-
import
|
|
1
|
+
import os
|
|
2
2
|
import sys
|
|
3
3
|
import shutil
|
|
4
|
+
import subprocess
|
|
4
5
|
import importlib.resources as resources
|
|
5
6
|
|
|
6
7
|
def execute_bash_script(script_name):
|
|
@@ -18,6 +19,8 @@ def execute_bash_script(script_name):
|
|
|
18
19
|
except FileNotFoundError:
|
|
19
20
|
raise FileNotFoundError(f"The script {script_name} does not exist or is not a file. Searched in package data.")
|
|
20
21
|
|
|
22
|
+
command_name = sys.argv[0]
|
|
23
|
+
os.environ["COMMAND_NAME"] = command_name
|
|
21
24
|
# Execute the bash script and stream output, merging stderr into stdout
|
|
22
25
|
process = subprocess.Popen(
|
|
23
26
|
[shutil.which("bash"), str(script_path)] + sys.argv[1:],
|