Translate the whole project to English and fix outdated comments and help

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>
This commit is contained in:
Antoine
2026-09-27 23:16:45 +02:00
parent cc1c22d2b8
commit fb892ea9f2
52 changed files with 4356 additions and 4323 deletions

View File

@ -135,10 +135,10 @@ tiles and maintains the pyramid at low priority — see `docs/MAPS.md`, section
### 3. Generating tiles from the map
The **+ Zone** ("Add area": draw a rectangle → IGN download + run on the
worker), **⤒ Compléter** ("Complete": already-downloaded but incomplete
tiles) and **↻ Générer cette dalle** ("Generate this tile": info panel on
click) buttons are hidden if:
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
@ -150,7 +150,7 @@ click) buttons are hidden if:
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
**Arrêter** ("Stop") button sends a SIGTERM to the pipeline. At the end of 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)

View File

@ -54,7 +54,11 @@ the reference tile above.
bundled in this image** (`filters.ground` / TIN missing) — would need to
be added to use it (or via lidR / a custom implementation).
## B. Fast hybrid (chosen for implementation)
## B. Fast hybrid (original plan, only partly kept)
> Only step 1 below is in use today. Step 2 (lowest-return floor) was
> dropped and step 3 (`_interpolate_holes`) is no longer called by the DTM
> builder: see "Synthesis / decision" for the current gap handling.
**PTD / Wack & Wimmer** principle (Wack & Wimmer 2002, *ISPRS Archives*
XXXIV/3A:293-296: DTM from lowest return, excluding the lowest 1% per cell
@ -66,10 +70,12 @@ to discard outliers):
*measured* ground where the vendor failed (rock outcrops, clearings,
forest floor).
3. **Topographic inpainting** of the remaining gaps (terrain-aware
interpolation already implemented in `dtm.py:_interpolate_holes`).
interpolation, `dtm.py:_interpolate_holes`, still present as a helper
but not called by `create_dtm_fast`).
Expected: **continuous** DTM (0% holes), robust in forest/relief,
**~10-15 s/tile** instead of 326-355 s. No GPU dependency, no training.
Expected at the time: **continuous** DTM (0% holes), robust in
forest/relief, **~10-15 s/tile** instead of 326-355 s. No GPU dependency,
no training.
## C. AI / ML models (supervised — require labels)
@ -115,18 +121,21 @@ deploy.
## Synthesis / decision
- "Fast" hard constraint + low maintenance → **fast hybrid (B)**
(~10-40 s/tile, zero training, zero GPU). ← **chosen approach, IMPLEMENTED**
- Base = IGN pre-classification (fast, ~10 s). `auto` prefers it as soon
as ≥ 20% of points are classified as ground (threshold lowered from 30%
to 20%, since the DTM is subsequently completed — see below).
(~10-40 s/tile, zero training, zero GPU). ← **chosen approach, base
IMPLEMENTED** (step 1 only, see below)
- Base = IGN pre-classification (fast: ~5 s with the direct laspy
extraction, vs ~13.5 s through PDAL). `auto` prefers it as soon as
≥ 20% of points are classified as ground (threshold lowered from 30%
to 20%).
- **This gap-filling note is superseded**: gap filling in the DTM is no
longer a distance-based `fillnodata` pass over small holes. It is now
a morphological closing bounded to the point envelope
(`_fill_small_gaps` in `dtm.py`): the closing radius follows the local
point spacing (measured over 5 m, staged at 1/1.5/2/3 m), nothing is
extended beyond measured pixels, and islands under 1 m² are removed.
Large holes (dense forest, steep relief where ground is
under-classified) still remain as nodata (black in the renders).
point spacing (1.5 × the spacing measured over 5 m, staged at
1/1.5/2/3 m), nothing is extended beyond measured pixels, and islands
under 1 m² are removed. Large holes (dense forest, steep relief where
ground is under-classified) still remain as nodata (dark grey in the
oriented relief, hatched in the PDF export).
Deliberately no floor at the lowest return: under dense canopy that
return is vegetation, which would print trees into the DTM.
- Maximum quality in hard cases (steep + dense), ~1-2 min/tile + GPU +

View File

@ -20,17 +20,17 @@ docker compose -f docker-compose.maps.yml logs -f maps
## Interface
A **single tabbed panel** (`web/map.{html,css,js}`) groups all settings,
replacing the old stack of stacked blocks: **Affichage** (Display) (main
layer, relief/precision mode, basemap), **Export PDF**, **Génération**
(Generation) (hidden if the generator is unavailable or not authorized for
that browser) and **Partager** (Share). On desktop, the panel occupies a
replacing the old stack of stacked blocks: **View** (main layer,
relief/precision mode, basemap), **Tile** (the selected tile's card),
**PDF** (PDF export), **Generate** (hidden if the generator is unavailable
or not authorized for that browser) and **Share**. On desktop, the panel occupies a
fixed column, collapsible into an icon strip (**‹**, always usable: clicking
a tab redeploys the panel). Below 720 px wide, it becomes a **bottom sheet**
with three heights — closed, half, full — changed by dragging the handle, by
simply tapping it (one notch), or by tapping the already-active tab again.
Clicking the map **selects** the LiDAR HD tile under the cursor (dashed
outline) and fills the **Dalle** (Tile) tab (footprint, IGN info, pass
outline) and fills the **Tile** tab (footprint, IGN info, pass
alignment) without changing the displayed tab; clicking the same tile again
deselects it, clicking another moves the selection. Keyboard shortcuts:
**1–5** (panel tabs, no effect if the tab is hidden), **P** (next display
@ -42,13 +42,13 @@ browsing).
## Generating tiles from the map
- **+ Zone** (Génération tab) — draw a rectangle: the 1 km LHD tiles it
- **+ Area** (Generate tab) — draw a rectangle: the 1 km LHD tiles it
intersects are downloaded from the IGN geoplatform and then processed
(0.2 m, options below); successive zones and clicks are additive;
- **⤒ Compléter** (Complete) — all tiles already present in `input/` that are
- **⤒ Complete** — all tiles already present in `input/` that are
missing at least one of the requested layers;
- **↻ Générer/Régénérer cette dalle** (Generate/Regenerate this tile) (button
on the tile sheet, Dalle tab) — a specific tile, even with no existing data.
- **↻ Generate/Regenerate this tile** (button on the tile card, Tile tab) —
a specific tile, even with no existing data.
Run options: target layers (default: the panel layers) and forced
regeneration. Ground classification (IGN, ground only) and edge stitching (a
@ -75,7 +75,7 @@ assets (`LIDAR_SOURCE_URL`).
|---|---|
| Projection | EPSG:3857, OSM XYZ scheme (north-west origin, `y` toward the south) |
| Canonical URL | `/tiles/{layer}/{z}/{x}/{y}.png` — 256 px, PNG RGBA |
| High-density variant | `/tiles/{layer}/{z}/{x}/{y}@2x.webp` — 512 px (internal interface) |
| High-density variant | `/tiles/{layer}/{z}/{x}/{y}@2x.avif` — 512 px AVIF (internal interface; png/webp also accepted) |
| Zoom levels | 5 → 19 native (0.2 m/px ≈ z19 in France); beyond that, client-side over-zoom |
| Outside coverage | fully transparent tile (overlayable), header `X-Tile-Empty: 1` |
| Pending (cache-only mode) | transparent tile, headers `X-Tile-Empty: 1` + `X-Tile-Pending: 1`, never cached by the browser |
@ -99,8 +99,8 @@ Discovery: `/tiles/{layer}.json` (TileJSON 3.0.0), `/tiles/wmts.xml`
- **uMap / MapLibre / Leaflet** — same XYZ template, or the TileJSON.
- **OsmAnd** — online tile source, XYZ template, max zoom 19.
The **"Utiliser dans JOSM / QGIS"** ("Use in JOSM / QGIS") button on the map
shows and copies these URLs for the selected layer.
The **XYZ imagery background** section of the map's **Share** tab shows
these URLs for the selected layer, with a **Copy** button for the XYZ template.
## Full pyramid pre-generated
@ -129,7 +129,7 @@ off is picked up on the next scan.
## Tile sheet and compass rose
Clicking the map selects the LiDAR HD tile under the cursor (dashed yellow
frame) and fills the **Dalle** (Tile) tab — name, Lambert 93 footprint, then,
frame) and fills the **Tile** tab — name, Lambert 93 footprint, then,
if the tile has been rendered, resolution, generation date and vertical pass
alignment (beams, offsets, line correction) — whether it has been generated
or not, without changing the displayed tab. IGN information arrives
@ -146,9 +146,9 @@ carries the local relief (light = bump, dark = hollow).
## Display: relief and precision
The map serves only the layers in `PANEL_VIZ` (`index.py`): the **relief
orienté** (oriented relief, the main display layer, which merges local
openness and slope orientation) and the **précision** (precision) layer
The map serves only the layers in `PANEL_VIZ` (`index.py`): the **oriented
relief** (`relief_oriente`, the main display layer, which merges local
openness and slope orientation) and the **precision** layer
(`densite_sol`: density of the ground points retained for the DTM). Other
visualizations present on disk are neither listed nor served as tiles.
@ -156,26 +156,26 @@ There is no more layer stack. The panel offers three modes, one click each,
or the **P** key to cycle to the next:
- **Relief** — the oriented relief alone;
- **Précision** (Precision) — density alone, in 16 shades of gray (fixed log
- **Precision** — density alone, in 16 shades of gray (fixed log
scale: level k starting at 0.25 × 2^(k/2) pts/m², black ≤ 0.35 or no
points, white ≥ 45); reads as a geometric-reliability map;
- **Comparer** (Compare) — a slider (mouse or touch) separates two layers
- **Compare** — a slider (mouse or touch) separates two layers
chosen from two menus (relief, precision, or bare OSM background) on
either side of the cursor; the same layer on both sides adds no split.
The Affichage (Display) tab also carries a **relief intensity** slider
The View tab also carries a **relief intensity** slider
(0.5×–2×, 1× by default): a comfort contrast applied to the displayed
layer's container (CSS `contrast()`), remembered and shared in the link
(`&I=`, written only if ≠ 1×) but never fixed as a server default nor
applied to the exported PDF (which keeps the standard render). A
collapsible **Comment lire la carte** (How to read the map) block reuses,
collapsible **How to read the map** block reuses,
for the displayed layer(s), the reading text from `VIZ_LEGENDS` (also served
by `/api/map/meta` and the TileJSON).
The precision legend (16 levels, tooltip in pts/m² on each level) is shown
as soon as precision is visible, either alone or on one side of the Compare
slider. LiDAR layers live in an **isolated** container (`isolation:
isolate`): the slider only splits the LiDAR layers, never the basemap.
slider. The slider clips only the LiDAR layers (a CSS `clip-path` on each
layer's container), never the basemap.
The share link carries the main layer, the mode, the comparison and the
intensity:
@ -186,10 +186,10 @@ ignored) open without error, in relief mode.
### Freezing the configuration
The **★ Définir par défaut** ("Set as default") button saves the current
The **★ Set as default** button saves the current
display — main layer, mode, basemap — to `output/.map-defaults.json` (never
the intensity, a per-browser comfort setting). Any browser with no local
setting then starts from this configuration; **↺ Réinitialiser** (Reset)
setting then starts from this configuration; **↺ Reset**
forgets the local state and reverts to it.
```bash
@ -205,7 +205,7 @@ the old stack (`order`/`on`/`blend`) is ignored, except for the basemap.
## PDF export (field print sheet)
The **Export PDF** tab shows the settings (A4/A3 format, landscape/portrait,
The **PDF** (PDF export) tab shows the settings (A4/A3 format, landscape/portrait,
scale 1:1,000 to 1:10,000, optional title) and, while it stays open, a
**dashed yellow frame** showing the area that will be printed (it disappears
when switching tabs). The frame is **anchored to the terrain**: it is
@ -214,11 +214,10 @@ position if it's still visible), the map zooms to show it in full above the
panel, and one can then navigate freely without it moving. It is moved by
dragging its **✥ handle** (mouse or touch); on release, the exact Lambert 93
geometry is recomputed (`GET /api/export/frame`) — a release immediately
followed by a click does not select a tile (300 ms guard). "⌖ Centrer ici"
("Center here") brings it back to the center of the view, "⤢ Voir le cadre"
("View the frame") zooms onto it; changing format, orientation or scale
followed by a click does not select a tile (300 ms guard). **⌖ Centre here**
brings it back to the center of the view, **⤢ Show frame** zooms onto it; changing format, orientation or scale
recenters the view. Settings and frame position are kept in the browser's
`localStorage`. **Exporter le PDF** ("Export PDF") downloads the sheet (`GET
`localStorage`. **Export PDF** downloads the sheet (`GET
/api/export/pdf`), named `relief_{x_km}_{y_km}_1-{scale}.pdf` (Lambert 93
center in km, to three decimal places).
@ -245,8 +244,7 @@ full image and on the Pi's lightweight image alone. Contents:
- a **quality panel**: a thumbnail of ground-point density (50 m cells,
color classes), key figures (average density, weakest cell, share of
interpolated area, acquisition period), areas **hatched in white** where
quality data is not available, and a "**Donnée manquante (sans relief)**"
("Missing data (no relief)") line listing the tiles in the area that
quality data is not available, and a "**Missing data (no relief)**" line listing the tiles in the area that
haven't been generated yet;
- a title block: title (by default, the list of covered tiles), scale,
format, dpi, L93 center, area size, export date and IGN source mention.
@ -376,7 +374,7 @@ environment:
|---|---|---|
| `LIDAR_TILE_BACKGROUND_MAX_Z` | native (`18` at @2x, `19` at 256 px) | maximum level maintained in the background, URL numbering |
| `LIDAR_TILE_BACKGROUND_SCALE` | `2` | tiles maintained: 2 = 512 px (the interface's) |
| `LIDAR_TILE_BACKGROUND_FMT` | `webp` | format of maintained tiles (the interface's) |
| `LIDAR_TILE_BACKGROUND_FMT` | `avif` | format of maintained tiles (the interface's) |
| `LIDAR_TILE_BACKGROUND_PAUSE` | `1.0` | pause (s) between two renders — the discretion lever |
| `LIDAR_TILE_BACKGROUND_INTERVAL` | `120` | seconds between two tile scans |
| `LIDAR_TILE_BACKGROUND_QUEUE_MAX` | `65536` | bounded queue — each tile remembers the first pyramid tile it was refused for lack of room and resumes from there on the next scans, until its whole pyramid has gone through |

Binary file not shown.

Before

Width:  |  Height:  |  Size: 712 KiB

After

Width:  |  Height:  |  Size: 733 KiB