Adding land features including lidar
This commit is contained in:
249
CLAUDE.md
249
CLAUDE.md
@@ -8,7 +8,7 @@ with AMD AI chip R9-8945HS with 32 GB ram
|
||||
|
||||
# Project: C++ OpenGL Radar Simulation
|
||||
**Environment:** Ubuntu Linux (Remote SSH from Windows)
|
||||
**Tech Stack:** C++20, OpenGL 3.3 Core, GLFW, GLAD, FreeType
|
||||
**Tech Stack:** C++20, OpenGL 3.3 Core, GLFW, GLAD, FreeType, GDAL (libgdal-dev)
|
||||
|
||||
|
||||
The operating system is Linux (Ubuntu)
|
||||
@@ -51,6 +51,15 @@ entire directory list is /home/maallyn/new-radar on the Geekom.
|
||||
./LICENSE
|
||||
./src
|
||||
./src/CLAUDE.md
|
||||
./map
|
||||
./map/lidar_processed
|
||||
./map/charts_enc
|
||||
./map/charts_enc/US5WA45M.000
|
||||
./map/charts_enc/n48_w123_1arc_v3.tif
|
||||
./map/lidar_raw
|
||||
./map/lidar_raw/wa2022_nooksack_dem_J1364940.zip
|
||||
./map/lidar_raw/wa2016_west_dem_J1364939.zip
|
||||
|
||||
|
||||
==================================================================
|
||||
|
||||
@@ -641,6 +650,16 @@ settings.h — tunable constants:
|
||||
- Rain clutter filter: default (0.0 = off), minimum (0.0), maximum (1.0), keyboard step size
|
||||
- Wave clutter filter: default (0.0 = off), minimum (0.0), maximum (1.0), keyboard step size
|
||||
- Key-hold acceleration for gain, rain clutter, and wave clutter keys
|
||||
- Terrain bounding box (lat/lon min/max) and processed cell size
|
||||
- Terrain material σ° values (soil, rock, concrete, water calm/rough)
|
||||
- Terrain material speckle/grain amplitudes (soil, rock, concrete)
|
||||
- Terrain classification thresholds (rock elevation, rock slope)
|
||||
- Terrain polar grid dimensions (range bins, bearing bins)
|
||||
- Terrain clutter brightness scale for marine PPI
|
||||
- Terrain boat recompute threshold (degrees bearing offset change)
|
||||
- ATC terrain clutter suppressed flag (bool, default true)
|
||||
- ATC terrain shadow enabled flag (bool, default true)
|
||||
- LiDAR structure height threshold for man-made classification
|
||||
|
||||
==================================================================
|
||||
|
||||
@@ -1055,6 +1074,220 @@ in settings.h so they can be tuned without touching equation code.
|
||||
|
||||
==================================================================
|
||||
|
||||
TERRAIN AND LAND CLUTTER
|
||||
|
||||
==================================================================
|
||||
|
||||
DATA SOURCES
|
||||
map/charts_enc/US5WA45M.000
|
||||
S-57 Electronic Navigational Chart; coastline polygon,
|
||||
pier/breakwater geometry, named landmarks. Parsed with GDAL/OGR.
|
||||
|
||||
map/charts_enc/n48_w123_1arc_v3.tif
|
||||
USGS 1 arc-second (~30 m) DEM GeoTIFF. Terrain elevation for the
|
||||
Bellingham area — Cascades, Chuckanut Mountain, coastal lowlands.
|
||||
|
||||
map/lidar_raw/wa2016_west_dem_J1364939.zip
|
||||
2016 western WA LiDAR DEM. Resolves waterfront structures,
|
||||
breakwaters, piers, Boulevard Park boardwalk, and other man-made
|
||||
features at ~1 m resolution.
|
||||
|
||||
map/lidar_raw/wa2022_nooksack_dem_J1364940.zip
|
||||
2022 Nooksack basin LiDAR DEM. Covers the delta and lowlands
|
||||
northeast of Bellingham Bay; used for terrain shadowing from the
|
||||
northeast quadrant.
|
||||
|
||||
All three sources are processed offline by terrain_preprocess into
|
||||
binary grids in map/lidar_processed/. The raw files are never opened
|
||||
at exhibit runtime. See TERRAIN PREPROCESSING section below.
|
||||
|
||||
GDAL (libgdal-dev) is a required build dependency for
|
||||
terrain_preprocess. It is NOT linked into the main radar binary.
|
||||
|
||||
CLASSES
|
||||
|
||||
TerrainMap (Thread 1, read-only after init)
|
||||
Loaded once at startup from map/lidar_processed/. Reads the four
|
||||
binary grids and the metadata JSON. Provides:
|
||||
- Elevation query by lat/lon
|
||||
- Material query by lat/lon
|
||||
- Pre-computed polar clutter grid (range × bearing bins) per
|
||||
fixed radar location
|
||||
- Line-of-sight shadow mask per radar location
|
||||
Thread 1 only after init; no mutex required.
|
||||
|
||||
LandClutter (Thread 1)
|
||||
Queries TerrainMap to generate clutter returns for each scope.
|
||||
Called once per full sweep rotation, not once per frame.
|
||||
- Marine A-Scope: produces amplitude samples along the current
|
||||
antenna bearing for injection into the range trace.
|
||||
- Marine PPI / ATC PPI: produces a polar texture (range × bearing)
|
||||
uploaded to the GPU once per sweep period.
|
||||
|
||||
TERRAIN MATERIALS AND RCS
|
||||
|
||||
Each terrain cell is classified as one of four materials. Normalized
|
||||
backscatter coefficient σ° (linear, m²/m²) is defined in settings.h:
|
||||
|
||||
TERRAIN_SIGMA0_SOIL ~0.010 (−20 dB) — moist vegetated soil
|
||||
TERRAIN_SIGMA0_ROCK ~0.032 (−15 dB) — exposed rock, rough face
|
||||
TERRAIN_SIGMA0_CONCRETE ~0.100 (−10 dB) — smooth hard surface;
|
||||
structures produce
|
||||
corner-reflector effect
|
||||
TERRAIN_SIGMA0_WATER_CALM ~0.0003 (−35 dB) — open water, calm;
|
||||
mostly specular, low
|
||||
backscatter
|
||||
TERRAIN_SIGMA0_WATER_ROUGH ~0.010 (−20 dB) — choppy sea, sea clutter
|
||||
|
||||
Classification rules applied by terrain_preprocess at build time:
|
||||
- Below sea level or inside S-57 coastline polygon → water
|
||||
- Inside S-57 pier/breakwater/wharf feature → concrete
|
||||
- Elevation > TERRAIN_ROCK_THRESHOLD_M AND slope
|
||||
> TERRAIN_ROCK_SLOPE_THRESHOLD_DEG → rock
|
||||
- All remaining land cells → soil
|
||||
|
||||
RADAR EQUATION FOR TERRAIN (area-extensive / clutter form)
|
||||
|
||||
P_r = (P_t × G² × λ² × σ° × A_cell) / ((4π)³ × R⁴)
|
||||
|
||||
A_cell is the terrain cell area projected along the beam.
|
||||
Evaluated CPU-side in LandClutter for each illuminated cell.
|
||||
Result drives per-cell brightness in the clutter texture.
|
||||
Same radar parameters (P_t, G, λ) used for point targets.
|
||||
|
||||
SHADOW / LINE-OF-SIGHT MASKING
|
||||
|
||||
Computed by terrain_preprocess for each fixed radar location and
|
||||
stored in the processed data as uint8 shadow masks. Algorithm: march
|
||||
outward from the radar along each azimuth radial, tracking the maximum
|
||||
elevation angle seen. Any cell whose surface angle falls below that
|
||||
maximum is shadowed — clutter amplitude = 0 and target returns through
|
||||
that cell are attenuated proportionally.
|
||||
|
||||
Shadow masks stored per radar location:
|
||||
map/lidar_processed/shadow_marine.u8 — marine bay platform
|
||||
map/lidar_processed/shadow_atc.u8 — BLI ATC tower
|
||||
|
||||
Bearing offset (k/j keys on PPI scopes):
|
||||
The k/j keys change display heading only — which direction appears
|
||||
at the top of the scope. They do NOT move the radar geographically.
|
||||
The shadow mask is unchanged. The terrain clutter shader receives
|
||||
the offset as a rotation uniform and samples the polar texture at
|
||||
the offset angle. Zero CPU overhead; no shadow recomputation.
|
||||
|
||||
Future boat scenario (not in v1):
|
||||
If the radar antenna physically moves to a new lat/lon, the shadow
|
||||
mask would be recomputed on a background thread while the display
|
||||
continues with the previous mask.
|
||||
|
||||
PER-SCOPE TERRAIN BEHAVIOR
|
||||
|
||||
Marine A-Scope:
|
||||
Land returns appear as stable blips at fixed ranges on the current
|
||||
antenna bearing. Concrete structures give strong returns; soil/hills
|
||||
give moderate returns; shadowed areas return nothing. Period
|
||||
operators were trained to discard stable blips when searching for
|
||||
moving targets.
|
||||
|
||||
Marine PPI (fixed platform and boat heading offset):
|
||||
Land clutter is fully visible. Coastline, hills, piers, and
|
||||
breakwaters paint exactly as on a real period marine radar. The
|
||||
clutter texture updates once per 4-second sweep rotation.
|
||||
|
||||
ATC PPI:
|
||||
Moving Target Indicator (MTI) cancellation suppresses land clutter.
|
||||
Controlled by ATC_TERRAIN_CLUTTER_SUPPRESSED (default true) in
|
||||
settings.h. Terrain shadowing of aircraft IS applied — controlled
|
||||
by ATC_TERRAIN_SHADOW_ENABLED (default true). Aircraft approaching
|
||||
behind a ridge appear at reduced amplitude or disappear until they
|
||||
clear the ridge, as on period ASR equipment.
|
||||
|
||||
Chain Home A-Scope:
|
||||
No terrain data applied. The exhibit scenario faces the English
|
||||
Channel; the transmitter floodlights the sea. Land returns are
|
||||
not simulated for this scope.
|
||||
|
||||
PAR:
|
||||
No terrain clutter. PAR points at a single fixed approach path;
|
||||
the narrow beam and short range make land returns negligible.
|
||||
|
||||
TERRAIN CLUTTER SHADER
|
||||
|
||||
terrain_clutter.vert / terrain_clutter.frag
|
||||
Renders the polar clutter texture as a quad overlay on the PPI
|
||||
scope. Converts screen coordinates to polar, samples the clutter
|
||||
texture, and outputs P7-compatible phosphor color and alpha so
|
||||
terrain returns decay on the same timescale as target echoes.
|
||||
Uniforms:
|
||||
u_bearingOffsetDeg — boat heading correction (default 0.0)
|
||||
u_clutterSuppressed — bool; 1 = suppress (ATC mode)
|
||||
u_maxRangeM — current scope max range in meters
|
||||
u_clutterBrightness — TERRAIN_MARINE_CLUTTER_BRIGHTNESS scale
|
||||
Used by MarinePPIScope and ATCPPIScope.
|
||||
|
||||
==================================================================
|
||||
|
||||
TERRAIN PREPROCESSING
|
||||
|
||||
==================================================================
|
||||
|
||||
The raw LiDAR zip files cannot be used at exhibit runtime. The offline
|
||||
tool terrain_preprocess processes them once and writes ready-to-use
|
||||
binary grids to map/lidar_processed/. Must be run before first launch
|
||||
and re-run whenever TERRAIN_BBOX_* or TERRAIN_PROCESSED_CELL_DEG
|
||||
constants in settings.h change.
|
||||
|
||||
TOOL
|
||||
Build target: terrain_preprocess (separate CMake executable)
|
||||
Source: src/terrain_preprocess.cpp
|
||||
Links: GDAL only; NOT linked into the main radar binary
|
||||
Run: ./terrain_preprocess (from build directory)
|
||||
|
||||
PIPELINE (runs in order)
|
||||
1. Unzip both LiDAR archives to a temp directory.
|
||||
2. Inventory tiles — enumerate .tif / .img files, check CRS and
|
||||
native resolution of each.
|
||||
3. Merge tiles within each survey into a GDAL VRT mosaic.
|
||||
4. Warp both surveys to WGS84 (EPSG:4326) at
|
||||
TERRAIN_PROCESSED_CELL_DEG resolution.
|
||||
5. Crop to bounding box: TERRAIN_BBOX_LAT_MIN/MAX,
|
||||
TERRAIN_BBOX_LON_MIN/MAX.
|
||||
6. Merge the two surveys — where they overlap, the 2022 Nooksack
|
||||
data wins over the 2016 western data (higher vintage / resolution).
|
||||
7. Material classification:
|
||||
Load S-57 ENC (US5WA45M.000) via GDAL/OGR.
|
||||
Apply classification rules described in TERRAIN section above.
|
||||
8. Compute shadow mask for marine platform and ATC tower using radial
|
||||
elevation-angle march along each azimuth bearing.
|
||||
9. Write to map/lidar_processed/:
|
||||
elevation.f32 float32 row-major grid, meters, WGS84
|
||||
material.u8 uint8 per cell (0=water 1=soil 2=rock 3=concrete)
|
||||
shadow_marine.u8 uint8 visibility mask for marine radar
|
||||
shadow_atc.u8 uint8 visibility mask for ATC radar
|
||||
terrain_meta.json grid dimensions, lat/lon origin, cell size,
|
||||
source file checksums, processing date
|
||||
|
||||
RUNTIME VALIDATION
|
||||
TerrainMap reads terrain_meta.json at startup and compares the stored
|
||||
bounding box and cell-size values against current settings.h constants.
|
||||
If they differ it prints a warning and continues with stale data:
|
||||
WARNING: terrain data was built with different bounding box or
|
||||
cell size — re-run terrain_preprocess before exhibit launch.
|
||||
The exhibit does not crash; it runs with the old grid.
|
||||
|
||||
OUTPUT FILES (map/lidar_processed/)
|
||||
elevation.f32 — float32 elevation grid
|
||||
material.u8 — uint8 material classification grid
|
||||
shadow_marine.u8 — uint8 line-of-sight mask, marine radar
|
||||
shadow_atc.u8 — uint8 line-of-sight mask, ATC radar
|
||||
terrain_meta.json — metadata and provenance record
|
||||
|
||||
These five files are the only terrain inputs at runtime.
|
||||
The raw zip archives in map/lidar_raw/ are never opened by
|
||||
the exhibit binary.
|
||||
|
||||
==================================================================
|
||||
|
||||
FILE LAYOUT (COMPLETE — including additions)
|
||||
|
||||
==================================================================
|
||||
@@ -1082,6 +1315,13 @@ src/
|
||||
rpi_receiver.h / rpi_receiver.cpp
|
||||
db_panel.h / db_panel.cpp — Dear ImGui DB management panel
|
||||
(--database mode only)
|
||||
terrain_map.h / terrain_map.cpp — DEM load, shadow mask, polar clutter
|
||||
grid; read-only after init, Thread 1
|
||||
land_clutter.h / land_clutter.cpp — per-sweep clutter arrays for A-scope
|
||||
range trace and PPI clutter texture
|
||||
terrain_preprocess.cpp — standalone offline preprocessing tool;
|
||||
separate CMake target; links GDAL only;
|
||||
NOT part of main radar binary
|
||||
settings.h — all constexpr constants; no .cpp
|
||||
|
||||
imgui/ — Dear ImGui source, compiled in
|
||||
@@ -1091,8 +1331,11 @@ src/
|
||||
imgui_draw.cpp / imgui_tables.cpp / imgui_widgets.cpp
|
||||
|
||||
shaders/
|
||||
phosphor.vert / phosphor.frag — P1 and P7 via uniforms
|
||||
phosphor.vert / phosphor.frag — P1 and P7 via uniforms
|
||||
graticule.vert / graticule.frag
|
||||
text.vert / text.frag
|
||||
sweep.vert / sweep.frag
|
||||
bloom.vert / bloom.frag — FBO bloom post-processing
|
||||
bloom.vert / bloom.frag — FBO bloom post-processing
|
||||
terrain_clutter.vert / terrain_clutter.frag — polar clutter texture overlay
|
||||
on PPI; P7-compatible decay;
|
||||
bearing offset rotation uniform
|
||||
|
||||
Reference in New Issue
Block a user