Comments, docstrings, logs, CLI help, map UI, legends, PDF sheet, scripts, compose files and AGENTS.md are now English. Data keys stay unchanged (relief_oriente, densite_sol, visualisations/, API JSON keys, link params). Wrong comments and help defaults found along the way are corrected. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
7.0 KiB
Two-machine deployment: lightweight map + processing worker
Two-machine architecture: the map (interface, XYZ tile pyramid, API) runs
on a Raspberry Pi; tile generation (IGN downloads, PDAL, GPU) runs on a
powerful machine. Both run the same server (lidar_pipeline.mapserve, image
lidar-maps), the powerful machine in its full version (pipeline included).
Browser ──HTTP──▶ Raspberry Pi (lightweight lidar-maps image, port 8975)
│ serves the map + the pyramid (cache-only + background
│ maintenance, LIDAR_TILE_CACHE_ONLY / LIDAR_TILE_BACKGROUND)
│ /api/generate, /api/preview, /api/status
│ └─ forwarded to ──▶ processing worker
│ tiles fetched back from the worker (LIDAR_SOURCE_URL:
│ /api/tiles inventory + versioned static assets)
▼
Processing worker (full image,
docker-compose.worker.yml service `worker`):
IGN download + GPU pipeline (tile generator)
+ tile pyramid + tile inventory
See also docs/MAPS.md for the map/tile-pyramid internals referenced below.
Processing worker (tile generator)
The worker service acts as the generator: it accepts generation requests
sent by remote maps (IGN download + PDAL/GPU processing), serves its own tile
pyramid and tile inventory (/api/tiles + static visualisations/,
index_thumbs/, index_subtiles/) that lightweight machines fetch on demand.
docker compose -f docker-compose.worker.yml up -d --build # API at http://<worker-ip>:8973
docker compose -f docker-compose.worker.yml logs -f worker
One-off batch processing of tiles already present in input/:
docker compose -f docker-compose.worker.yml run --rm --build process [-r 0.2 | --force]
On a machine without a GPU: remove the gpus: all lines (CPU processing,
slower). Optional but recommended if the network isn't trusted: protect the
API with a shared token — uncomment in docker-compose.worker.yml:
environment:
- LIDAR_API_TOKEN=a-secret-to-share
Raspberry Pi (lightweight map)
0. Prerequisites on the Pi
- Architecture: the image is built natively on the machine (ARM64 or
x86_64, check with
uname -m). The build happens on the Pi itself (Dockerfile.maps:python:3.12-slimbase, ~200 MB, no PDAL/GDAL). - Docker + compose plugin: official install
docs.docker.com/engine/install
(verify with
docker compose version). - Disk space: plan for the cache size (fetched tiles + rendered tiles;
use the size of
output/on the processing machine as a reference).
1. Copy the code onto the Pi (git clone)
git clone https://github.com/<you>/lidar_rendu.git lidar
cd lidar
output/ and input/ are git-ignored: the repository only holds the code,
the cache fills on demand from the processing machine.
2. Start the map
docker-compose.maps.yml (versioned) serves as the base; the Pi's local
configuration lives in an override file docker-compose.maps.override.yml
(not versioned). Start from the provided template:
cp docker-compose.maps.override.yml.example docker-compose.maps.override.yml
It looks like this (adapt addresses, cache folder and Traefik routing):
name: lidar-maps
services:
maps:
volumes: !override # Compose >= 2.24 (replaces ./output)
- /srv/lidar/output:/data/output
mem_limit: 1g
memswap_limit: 1g
environment:
- TZ=Europe/Paris
- LIDAR_SOURCE_URL=http://192.168.1.50:8973 # worker (tiles + inventory)
- LIDAR_GENERATION_URL=http://192.168.1.50:8973 # worker (delegated generation)
# - LIDAR_REMOTE_TOKEN=a-secret-to-share # if LIDAR_API_TOKEN is set on the worker
- LIDAR_TILE_WORKERS=1
- LIDAR_TILE_SOURCE_CACHE_MB=64
- LIDAR_TILE_CACHE_ONLY=1 # browsing renders NOTHING
- LIDAR_TILE_BACKGROUND=1 # the pyramid is maintained as a background task
- LIDAR_TILE_BACKGROUND_PAUSE=1.0
networks: [webapp, proxy]
labels: # optional Traefik routing
- "traefik.enable=true"
- "traefik.http.routers.lidar-maps.rule=Host(`lidar.example.fr`)"
- "traefik.http.routers.lidar-maps.entrypoints=websecure"
- "traefik.http.routers.lidar-maps.tls.certresolver=myresolver"
- "traefik.http.services.lidar-maps.loadbalancer.server.port=8975"
networks:
webapp:
name: lidar_rendu_default
external: true
proxy:
name: proxy
external: true
mkdir -p /srv/lidar/output # owned by uid 1000 (container)
docker compose -f docker-compose.maps.yml -f docker-compose.maps.override.yml up -d --build
The map is available at http://<pi-host>:8975/ (and via Traefik if
configured).
LIDAR_TILE_CACHE_ONLY=1 + LIDAR_TILE_BACKGROUND=1 flip the load pattern on
a small Pi: browsing renders nothing (a missing tile is served transparent,
with X-Tile-Pending), and a background task watches for new or regenerated
tiles and maintains the pyramid at low priority — see docs/MAPS.md, section
"Cache-only + background maintenance".
3. Generating tiles from the map
The Generation tab (+ Area: draw a rectangle → IGN download + run on the worker; ⤒ Complete: already-downloaded but incomplete tiles) and the ↻ Generate this tile button (Tile tab, after clicking a tile) are hidden if:
- the browser's IP is outside
LIDAR_REGEN_CIDR(default: loopback + private RFC1918 ranges; a comma-separated list of CIDRs, or an empty string to lift the restriction). The IP is the one seen on the connection (preserved by Docker's DNAT for LAN clients); behind a local reverse proxy (itself inside the allowed network),X-Forwarded-Fordesignates the real client; - the worker is unreachable AND no local pipeline exists.
A request submitted while a run is already in progress is placed in a queue on the worker side (an in-progress job is never interrupted); progress is displayed tile by tile (orange/blue/red frames on the map) and the Stop button sends a SIGTERM to the pipeline. At the end of the run, the map refreshes and pyramid maintenance resumes automatically.
4. Centering the map on the GPS position (phone)
Browsers only expose the Geolocation API in a secure context (HTTPS):
serve the map behind Traefik (TLS) as above, or, as a last resort, directly
over HTTPS (the standalone entry point python -m lidar_pipeline.mapserve
honors LIDAR_SSL_CERTFILE / LIDAR_SSL_KEYFILE).
Updating
Processing machine
cd <checkout> && git pull && docker compose -f docker-compose.worker.yml up -d --build
Pi
ssh <pi-host> "cd <checkout> && git pull && docker compose -f docker-compose.maps.yml -f docker-compose.maps.override.yml up -d --build"
The interface code is baked into the image (Dockerfile.maps): ANY
interface change requires a rebuild (--build) — without it, the old code
keeps running.