feat(coverage): per-pixel clutter model from NLCD land cover#457
Merged
SimmerV merged 15 commits intoMeshAddicts:developfrom May 7, 2026
Merged
feat(coverage): per-pixel clutter model from NLCD land cover#457SimmerV merged 15 commits intoMeshAddicts:developfrom
SimmerV merged 15 commits intoMeshAddicts:developfrom
Conversation
Contributor
There was a problem hiding this comment.
Pull request overview
This PR upgrades the Coverage + Scan propagation model from a legacy flat “environment clutter” offset to a per-pixel clutter-loss model driven by USGS NLCD land-cover tiles, and adds the operator tooling + docs needed to bake/serve those tiles.
Changes:
- Add an NLCD tile bake pipeline (Python script + dedicated Docker bake image/profile) and mount baked tiles from the API at
/tiles/landcover. - Implement frontend landcover tile fetching/caching and integrate ITU-R P.452/P.833 clutter loss into both coverage raster rendering and scan analysis, with new UI controls + persisted state.
- Add/refresh operator documentation and adjust attribution UI behavior.
Reviewed changes
Copilot reviewed 30 out of 31 changed files in this pull request and generated 10 comments.
Show a summary per file
| File | Description |
|---|---|
| scripts/requirements-landcover.txt | Adds bake-script Python dependencies (not installed in prod image). |
| scripts/README-landcover.md | Operator runbook for baking and serving NLCD tiles. |
| scripts/landcover_tiles.py | New multiprocess NLCD→slippy PNG tile baker with download+resume. |
| RF-MODEL.md | New public-facing RF model explainer (ITM + ITU clutter + NLCD). |
| README.md | Documents the new RF model + one-command bake flow. |
| frontend/src/pages/NodeMap.tsx | Collapses MapLibre attribution control by default via MutationObserver. |
| frontend/src/pages/map/storage.ts | Adds localStorage keys for clutter enable + aggression per tool. |
| frontend/src/pages/map/scanAnalysis.ts | Replaces flat clutter offset with per-path clutter loss from NLCD raster. |
| frontend/src/pages/map/MapScanPanel.tsx | Replaces “Environment” preset UI with clutter toggle + aggression + status + legend. |
| frontend/src/pages/map/MapLosPanel.tsx | Import ordering tweak. |
| frontend/src/pages/map/MapDetailsPanel.tsx | Import list updated (minor formatting). |
| frontend/src/pages/map/MapCoveragePanel.tsx | Replaces “Environment” preset UI with clutter toggle + aggression + status + legend. |
| frontend/src/pages/map/landcoverTiles.ts | New NLCD tile fetcher + LRU cache + raster builder + sampling utilities. |
| frontend/src/pages/map/landcoverTiles.test.ts | Unit tests for zoom selection, sampling, and missing-tile behavior. |
| frontend/src/pages/map/coverageSliceWorker.ts | Threads an optional clutter buffer through the coverage worker. |
| frontend/src/pages/map/coverageRaster.ts | Integrates per-pixel clutter loss into raster rendering parameters/loop. |
| frontend/src/pages/map/coverageAnalysis.ts | Replaces ENVIRONMENTS with AGGRESSION_STOPS + defaults/heuristics. |
| frontend/src/pages/map/ClutterUI.tsx | Shared clutter UI components (slider, status chip, class legend). |
| frontend/src/pages/map/clutterPath.ts | Implements endpoint + path-integrated clutter loss computation. |
| frontend/src/pages/map/clutterPath.test.ts | Unit tests for clutter-path math and scratch-buffer behavior. |
| frontend/src/pages/map/clutterClasses.ts | Defines NLCD class parameter table + ITU math helpers. |
| frontend/src/pages/map/clutterClasses.test.ts | Unit tests for ITU math + table integrity. |
| frontend/src/pages/Map.tsx | Wires clutter raster build into coverage+scan, adds UI state + telemetry plumbing. |
| frontend/src/maps/mapStyle.ts | Removes Tilezen DEM attribution string from the style source spec. |
| Dockerfile.landcover | New one-shot bake image to keep prod image lean. |
| docker-compose.yml | Adds landcover-bake service behind a bake profile. |
| docker-compose-dev.yml | Adds landcover-bake service behind a bake profile (dev compose). |
| config.toml.sample | Adds [landcover] configuration stanza and operator guidance comments. |
| config.py | Adds default landcover config fields to DEFAULT_CONFIG. |
| api/api.py | Mounts baked landcover tiles and sets long-lived cache headers. |
| .gitignore | Ignores docs/ directory. |
💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Summary
docker compose --profile bake run --rm landcover-bakeauto-downloads NLCD 2024 from MRLC and bakes the tile pyramid. Skip the bake and coverage falls back to a "Mixed Forest" default everywhere, with a clear amber status chip telling the operator how to enable.Architecture
Frontend math — new
clutterClasses.ts(NLCD class table + ITU formulas, citations on every row) andclutterPath.ts(per-pixel orchestration: P.452 endpoints + P.833 path integration with asymmetricd_kendpoint exclusion and canonical-id scratch buffer reused across pixels).Frontend wiring —
landcoverTiles.ts(LRU-cached slippy fetcher,buildClutterRasterwith nearest-neighbor categorical resampling, downsampler for drag preview). Worker plumbing extended with a clutter buffer alongside the existing DEM.Map.tsxbuilds DEM + clutter in parallel, threads through to the worker pool, capturestilesPresent / tilesTotaltelemetry for the status chip.Backend — new
/tiles/landcoverstatic mount inapi/api.pywith year-long immutable cache. Newscripts/landcover_tiles.pyone-shot bake: auto-download with HTTP Range resume, zip extraction, multi-process tile generation (~16 min CONUS on 32 threads). NewDockerfile.landcover+landcover-bakecompose service underprofiles: ["bake"]so the bake doesn't run as part of normaldocker compose up.Docs — new top-level
RF-MODEL.md(public-facing model explainer),scripts/README-landcover.mdrewritten with the one-command flow as the headline, top-levelREADME.mdupdated.Side improvements