Skip to content

Add offline map tile prefetch tooling#18

Open
brothercorvo wants to merge 2 commits intotorlando-tech:mainfrom
brothercorvo:codex/map-prefetch-offline-20260316
Open

Add offline map tile prefetch tooling#18
brothercorvo wants to merge 2 commits intotorlando-tech:mainfrom
brothercorvo:codex/map-prefetch-offline-20260316

Conversation

@brothercorvo
Copy link
Copy Markdown

Summary

  • add ools/prefetch_map_tiles.py to download Pyxis-compatible XYZ PNG tiles into iles/{z}/{x}/{y}.png
  • add ools/README.md describing the defaults, radius-based area selection, and SD card layout
  • include the additional staged repo updates requested during branch preparation

Notes

  • the script defaults to the coordinates shown in the provided screenshot and a 200 km radius
  • output matches the firmware map loader format directly

Testing

  • not run

@greptile-apps
Copy link
Copy Markdown
Contributor

greptile-apps Bot commented Mar 16, 2026

Greptile Summary

Adds a Python script (tools/prefetch_map_tiles.py) and documentation (tools/README.md) for downloading XYZ map tiles into the tiles/{z}/{x}/{y}.png directory structure expected by the Pyxis firmware's SD card loader. Also bumps the deps/microReticulum submodule and updates .gitignore.

  • OpenStreetMap policy violation: The script defaults to bulk-downloading ~55,000 tiles from tile.openstreetmap.org, which explicitly prohibits bulk downloading, scraping, and offline prefetching. The default URL template should be changed to a self-hosted or permissively-licensed tile server, and the README should warn users accordingly.
  • Log files committed: prefetch_map_tiles.stderr.log and prefetch_map_tiles.stdout.log are runtime artifacts from a test run and should be removed from the repository and added to .gitignore.
  • Antimeridian edge case: enumerate_tiles() does not handle bounding boxes that wrap around the 180° meridian, which would produce incorrect tile ranges for users near the dateline.

Confidence Score: 2/5

  • This PR should not be merged as-is due to the OSM tile usage policy violation and committed log files.
  • The core script logic (tile math, haversine, download with retries) is well-implemented, but the default configuration actively violates OpenStreetMap's tile usage policy by bulk-downloading ~55k tiles. This could get the project's users IP-blocked and reflects poorly on the project. Additionally, runtime log files were accidentally committed.
  • tools/prefetch_map_tiles.py (OSM policy violation in default URL template), prefetch_map_tiles.stderr.log and prefetch_map_tiles.stdout.log (should not be in repo)

Important Files Changed

Filename Overview
tools/prefetch_map_tiles.py New tile prefetch script with correct tile math and download logic, but defaults to OpenStreetMap's tile server which explicitly prohibits bulk downloading. Antimeridian wrapping edge case not handled.
tools/README.md Documentation for the prefetch script. Missing warning about OSM tile usage policy restrictions on bulk/offline downloads.
prefetch_map_tiles.stderr.log Runtime log file accidentally committed to the repository. Should be removed and gitignored.
prefetch_map_tiles.stdout.log Runtime log file accidentally committed to the repository. Should be removed and gitignored.
.gitignore Adds /tiles/ and deps/microReticulum to gitignore. Correct, but log files should also be gitignored.
deps/microReticulum Submodule pointer updated to a newer commit. Unrelated to the tile prefetch feature but bundled in the same PR.

Flowchart

%%{init: {'theme': 'neutral'}}%%
flowchart TD
    A[Parse CLI args] --> B[Compute bounding box from center + radius]
    B --> C[For each zoom level z8..z14]
    C --> D[Enumerate tiles intersecting radius]
    D --> E{Dry run?}
    E -- Yes --> F[Print tile counts and exit]
    E -- No --> G[For each tile x,y]
    G --> H{File exists locally?}
    H -- Yes --> I[Skip]
    H -- No --> J[Build URL from template]
    J --> K[Download tile with retries]
    K --> L{Success?}
    L -- Yes --> M[Write to tiles/z/x/y.png]
    L -- No --> N[Log failure to stderr]
    M --> O[Sleep delay]
    N --> O
    O --> G
    I --> G
Loading
Prompt To Fix All With AI
This is a comment left during a code review.
Path: tools/prefetch_map_tiles.py
Line: 36

Comment:
**Violates OpenStreetMap tile usage policy**

The default `--url-template` points to `tile.openstreetmap.org`, which [explicitly prohibits](https://operations.osmfoundation.org/policies/tiles/) bulk downloading and offline prefetching:

> **You must not:** Bulk download ("scrape") tiles or offer prefetch features.
>
> **Offline use is not permitted** on `tile.openstreetmap.org`. Features such as "Download city/country for offline use" [...] Note: If you require offline maps, use self-hosted tiles or a provider that explicitly allows offline/prefetching.

At the default settings (zoom 8–14, 200 km radius), this script downloads ~55,000 tiles in a single run, which will very likely get the user's IP blocked.

Consider changing the default URL template to a placeholder or a self-hosted tile server, and add a prominent warning in both the script's `--help` output and the README that users must use a tile provider that permits bulk/offline downloads (e.g., a self-hosted tile server, Thunderforest with an appropriate plan, or MapTiler).

How can I resolve this? If you propose a fix, please make it concise.

---

This is a comment left during a code review.
Path: prefetch_map_tiles.stderr.log
Line: 1-16

Comment:
**Log files should not be committed**

These log files (`prefetch_map_tiles.stderr.log` and `prefetch_map_tiles.stdout.log`) are runtime output artifacts from a test run and should not be tracked in the repository. Consider removing them from the commit and adding `*.log` or these specific filenames to `.gitignore`.

How can I resolve this? If you propose a fix, please make it concise.

---

This is a comment left during a code review.
Path: tools/prefetch_map_tiles.py
Line: 187-202

Comment:
**Antimeridian wrapping not handled**

If the bounding box wraps around the antimeridian (e.g., center near lon=179° with a large radius), `bounding_box()` returns `west > east` after normalization (e.g., `west=170`, `east=-170`). In that case, `latlon_to_tile(north, west)` produces a high `x0` and `latlon_to_tile(south, east)` produces a low `x1`. The subsequent `min(x0, x1)` / `max(x0, x1)` logic would then scan nearly the entire x-range of the globe rather than the two small strips near the antimeridian.

This isn't a problem for the current default coordinates (eastern Canada), but it will produce incorrect results for any user who specifies a center point near the dateline. If this is a known limitation, it's worth documenting; otherwise, the function needs to detect the wrap and split the x-range into two segments.

How can I resolve this? If you propose a fix, please make it concise.

---

This is a comment left during a code review.
Path: tools/README.md
Line: 53-54

Comment:
**Missing OSM tile usage policy warning**

The README should note that the default tile server (`tile.openstreetmap.org`) prohibits bulk downloading and offline prefetching per the [OSM Tile Usage Policy](https://operations.osmfoundation.org/policies/tiles/). Users should be directed to use a self-hosted tile server or a provider that explicitly permits offline/bulk downloads.

How can I resolve this? If you propose a fix, please make it concise.

Last reviewed commit: 3e336a4

DEFAULT_RADIUS_KM = 200.0
DEFAULT_MIN_ZOOM = 8
DEFAULT_MAX_ZOOM = 14
DEFAULT_URL_TEMPLATE = "https://tile.openstreetmap.org/{z}/{x}/{y}.png"
Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Violates OpenStreetMap tile usage policy

The default --url-template points to tile.openstreetmap.org, which explicitly prohibits bulk downloading and offline prefetching:

You must not: Bulk download ("scrape") tiles or offer prefetch features.

Offline use is not permitted on tile.openstreetmap.org. Features such as "Download city/country for offline use" [...] Note: If you require offline maps, use self-hosted tiles or a provider that explicitly allows offline/prefetching.

At the default settings (zoom 8–14, 200 km radius), this script downloads ~55,000 tiles in a single run, which will very likely get the user's IP blocked.

Consider changing the default URL template to a placeholder or a self-hosted tile server, and add a prominent warning in both the script's --help output and the README that users must use a tile provider that permits bulk/offline downloads (e.g., a self-hosted tile server, Thunderforest with an appropriate plan, or MapTiler).

Prompt To Fix With AI
This is a comment left during a code review.
Path: tools/prefetch_map_tiles.py
Line: 36

Comment:
**Violates OpenStreetMap tile usage policy**

The default `--url-template` points to `tile.openstreetmap.org`, which [explicitly prohibits](https://operations.osmfoundation.org/policies/tiles/) bulk downloading and offline prefetching:

> **You must not:** Bulk download ("scrape") tiles or offer prefetch features.
>
> **Offline use is not permitted** on `tile.openstreetmap.org`. Features such as "Download city/country for offline use" [...] Note: If you require offline maps, use self-hosted tiles or a provider that explicitly allows offline/prefetching.

At the default settings (zoom 8–14, 200 km radius), this script downloads ~55,000 tiles in a single run, which will very likely get the user's IP blocked.

Consider changing the default URL template to a placeholder or a self-hosted tile server, and add a prominent warning in both the script's `--help` output and the README that users must use a tile provider that permits bulk/offline downloads (e.g., a self-hosted tile server, Thunderforest with an appropriate plan, or MapTiler).

How can I resolve this? If you propose a fix, please make it concise.

Comment on lines +1 to +16
FAIL https://tile.openstreetmap.org/13/2552/2984.png -> tiles\13\2552\2984.png (HTTP Error 404: Not Found)
FAIL https://tile.openstreetmap.org/13/2552/2985.png -> tiles\13\2552\2985.png (HTTP Error 404: Not Found)
FAIL https://tile.openstreetmap.org/13/2552/2986.png -> tiles\13\2552\2986.png (HTTP Error 404: Not Found)
FAIL https://tile.openstreetmap.org/13/2552/2987.png -> tiles\13\2552\2987.png (HTTP Error 404: Not Found)
FAIL https://tile.openstreetmap.org/13/2552/2988.png -> tiles\13\2552\2988.png (HTTP Error 404: Not Found)
FAIL https://tile.openstreetmap.org/13/2552/2989.png -> tiles\13\2552\2989.png (HTTP Error 404: Not Found)
FAIL https://tile.openstreetmap.org/13/2552/2990.png -> tiles\13\2552\2990.png (HTTP Error 404: Not Found)
FAIL https://tile.openstreetmap.org/13/2552/2991.png -> tiles\13\2552\2991.png (HTTP Error 404: Not Found)
FAIL https://tile.openstreetmap.org/13/2553/2984.png -> tiles\13\2553\2984.png (HTTP Error 404: Not Found)
FAIL https://tile.openstreetmap.org/13/2553/2985.png -> tiles\13\2553\2985.png (HTTP Error 404: Not Found)
FAIL https://tile.openstreetmap.org/13/2553/2986.png -> tiles\13\2553\2986.png (HTTP Error 404: Not Found)
FAIL https://tile.openstreetmap.org/13/2553/2987.png -> tiles\13\2553\2987.png (HTTP Error 404: Not Found)
FAIL https://tile.openstreetmap.org/13/2553/2988.png -> tiles\13\2553\2988.png (HTTP Error 404: Not Found)
FAIL https://tile.openstreetmap.org/13/2553/2989.png -> tiles\13\2553\2989.png (HTTP Error 404: Not Found)
FAIL https://tile.openstreetmap.org/13/2553/2990.png -> tiles\13\2553\2990.png (HTTP Error 404: Not Found)
FAIL https://tile.openstreetmap.org/13/2553/2991.png -> tiles\13\2553\2991.png (HTTP Error 404: Not Found)
Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Log files should not be committed

These log files (prefetch_map_tiles.stderr.log and prefetch_map_tiles.stdout.log) are runtime output artifacts from a test run and should not be tracked in the repository. Consider removing them from the commit and adding *.log or these specific filenames to .gitignore.

Prompt To Fix With AI
This is a comment left during a code review.
Path: prefetch_map_tiles.stderr.log
Line: 1-16

Comment:
**Log files should not be committed**

These log files (`prefetch_map_tiles.stderr.log` and `prefetch_map_tiles.stdout.log`) are runtime output artifacts from a test run and should not be tracked in the repository. Consider removing them from the commit and adding `*.log` or these specific filenames to `.gitignore`.

How can I resolve this? If you propose a fix, please make it concise.

Comment on lines +187 to +202
def enumerate_tiles(center_lat: float, center_lon: float, radius_km: float, zoom: int) -> list[tuple[int, int]]:
south, west, north, east = bounding_box(center_lat, center_lon, radius_km)
x0, y1 = latlon_to_tile(north, west, zoom)
x1, y0 = latlon_to_tile(south, east, zoom)
max_index = (1 << zoom) - 1
x_start = max(0, min(x0, x1))
x_end = min(max_index, max(x0, x1))
y_start = max(0, min(y0, y1))
y_end = min(max_index, max(y0, y1))

tiles: list[tuple[int, int]] = []
for tile_x in range(x_start, x_end + 1):
for tile_y in range(y_start, y_end + 1):
if tile_intersects_radius(center_lat, center_lon, radius_km, tile_x, tile_y, zoom):
tiles.append((tile_x, tile_y))
return tiles
Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Antimeridian wrapping not handled

If the bounding box wraps around the antimeridian (e.g., center near lon=179° with a large radius), bounding_box() returns west > east after normalization (e.g., west=170, east=-170). In that case, latlon_to_tile(north, west) produces a high x0 and latlon_to_tile(south, east) produces a low x1. The subsequent min(x0, x1) / max(x0, x1) logic would then scan nearly the entire x-range of the globe rather than the two small strips near the antimeridian.

This isn't a problem for the current default coordinates (eastern Canada), but it will produce incorrect results for any user who specifies a center point near the dateline. If this is a known limitation, it's worth documenting; otherwise, the function needs to detect the wrap and split the x-range into two segments.

Prompt To Fix With AI
This is a comment left during a code review.
Path: tools/prefetch_map_tiles.py
Line: 187-202

Comment:
**Antimeridian wrapping not handled**

If the bounding box wraps around the antimeridian (e.g., center near lon=179° with a large radius), `bounding_box()` returns `west > east` after normalization (e.g., `west=170`, `east=-170`). In that case, `latlon_to_tile(north, west)` produces a high `x0` and `latlon_to_tile(south, east)` produces a low `x1`. The subsequent `min(x0, x1)` / `max(x0, x1)` logic would then scan nearly the entire x-range of the globe rather than the two small strips near the antimeridian.

This isn't a problem for the current default coordinates (eastern Canada), but it will produce incorrect results for any user who specifies a center point near the dateline. If this is a known limitation, it's worth documenting; otherwise, the function needs to detect the wrap and split the x-range into two segments.

How can I resolve this? If you propose a fix, please make it concise.

Comment thread tools/README.md
Comment on lines +53 to +54
- The script defaults to the same OpenStreetMap tile URL currently used by the firmware.
- If you use a different tile provider, pass `--url-template`.
Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Missing OSM tile usage policy warning

The README should note that the default tile server (tile.openstreetmap.org) prohibits bulk downloading and offline prefetching per the OSM Tile Usage Policy. Users should be directed to use a self-hosted tile server or a provider that explicitly permits offline/bulk downloads.

Prompt To Fix With AI
This is a comment left during a code review.
Path: tools/README.md
Line: 53-54

Comment:
**Missing OSM tile usage policy warning**

The README should note that the default tile server (`tile.openstreetmap.org`) prohibits bulk downloading and offline prefetching per the [OSM Tile Usage Policy](https://operations.osmfoundation.org/policies/tiles/). Users should be directed to use a self-hosted tile server or a provider that explicitly permits offline/bulk downloads.

How can I resolve this? If you propose a fix, please make it concise.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant