diff --git a/CLAUDE.md b/CLAUDE.md index 101cf00..d06b569 100644 --- a/CLAUDE.md +++ b/CLAUDE.md @@ -215,9 +215,10 @@ should be articulated in the descriptive text Let's assign key . for toggling between 25 and 12.5 PRF. There is no range selection. Note on description; this is to reduce use of the shift key. - Because of the slow repetition rate, the phosphor used was an early implementation - of the p7 phosphor so that the targets will still glow between the sweeps and not cause - flickering. + Because of the slow repetition rate, the phosphor used was P2 (long-persistence green) + so that the targets will still glow between the sweeps and not cause flickering. P2 is + a single-layer green phosphor with longer decay than P1, appropriate for an A-scope at + low PRF. Unlike P7, it does not produce a blue flash or a seconds-long smearing tail. Another unique feature would be a response to the drifting problem in early electronics. The scope electronics would use a crystal calibrator that puts tiny pips or spikes at @@ -235,7 +236,23 @@ should be articulated in the descriptive text presentation. All are P7 phosphor. Immediate strike by the electron beam is blue. persistence is green/yellow. Targets, range rings, and range ring labels shall all persist and fade out together. They should be faded out by the time the sweep - to that location. + returns to that location. + + IMPORTANT — range rings are beam-painted, not a static overlay: + Range rings and their labels are written by the rotating sweep beam on + each pass, exactly like target echoes. They are NOT rendered as a fixed + overlay on top of the scope. This means they are fully subject to P7 + persistence and decay just as targets are. + + When the operator changes max range (u/d keys), the new ring geometry + takes effect only for the sector the sweep is currently painting. The + rest of the scope still holds the old ring positions in the phosphor, + glowing and fading normally. As the sweep continues rotating, each + sector it reaches is repainted with the new ring geometry, replacing the + old. One full sweep rotation after the change, the transition is complete + and only the new rings remain. This is physically correct — the phosphor + holds whatever the beam last wrote. No special transition animation is + needed; the behavior emerges naturally from the phosphor model. The maximum range settings are 6 miles for the marine radar scope Rings should be 2,4, and 6 miles for marine. @@ -619,7 +636,7 @@ AScope : public Scope (abstract) — shared A-scope behavior: - Noise floor rendering (rain/wave clutter) - Incandescent graticule (three horizontal amplitude lines + vertical range lines) - Bearing control with key-hold acceleration - - Phosphor type as parameter (P1 or P7) + - Phosphor type as parameter (P1, P2, or P7) MarineAScope : public AScope - P1 phosphor (green) @@ -630,7 +647,7 @@ MarineAScope : public AScope u and d ignored during graticule swap animation ChainHomeAScope : public AScope - - P7 phosphor (early implementation) + - P2 phosphor (long-persistence green) - Goniometer state: H/V mode toggle, azimuth angle, elevation angle - PRF toggle: 25 Hz / 12.5 Hz - Calibrator stretch/shrink scale factor @@ -644,6 +661,11 @@ PPIScope : public Scope (abstract) — shared PPI behavior: - Cursor range/bearing readout under scope (white text) - Bearing offset for boat mode (k/j) - Cursor range clamped to max range + - Range rings and labels are beam-painted per sweep sector, NOT a static overlay; + the sweep shader evaluates ring radii for the CURRENT max range at the moment + each beam angle is rendered; the phosphor buffer retains whatever was last + written, so old ring positions fade naturally as the sweep overwrites them with + new geometry — no special transition code required MarinePPIScope : public PPIScope - Sweep time: 4 seconds @@ -735,7 +757,8 @@ settings.h — tunable constants: includes settings.h. No values are hardcoded elsewhere. Categories planned: - Phosphor P1 color - - Phosphor P7 strike color, persistence color, decay times (PPI and Chain Home) + - Phosphor P2 color and decay time (Chain Home A-Scope) + - Phosphor P7 strike color, persistence color, decay times (PPI scopes and PAR) - Sweep line width, brightness, fade trail, periods per scope - PAR scan rate; Chain Home PRF high and low - Graticule incandescent color, line widths @@ -1459,11 +1482,24 @@ 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. +All three raw terrain sources are processed in a single pass by the +offline tool terrain_preprocess, which 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. + +Sources processed: + map/charts_enc/n48_w123_1arc_v3.tif — USGS 1 arc-second DEM + (~30 m); already WGS84; + covers full ATC radar range + including distant ridges + map/lidar_raw/wa2016_west_dem_J1364939.zip — 2016 LiDAR DEM (~1 m); + projected; requires warp + map/lidar_raw/wa2022_nooksack_dem_J1364940.zip — 2022 LiDAR DEM (~1 m); + projected; requires warp + map/charts_enc/US5WA45M.000 — S-57 ENC; material + classification only; no + elevation data TOOL Build target: terrain_preprocess (separate CMake executable) @@ -1472,16 +1508,22 @@ TOOL 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). + 1. Open USGS DEM (n48_w123_1arc_v3.tif) directly via GDAL — already + in WGS84, no warp needed. Crop to TERRAIN_BBOX_LAT/LON bounds. + 2. Unzip both LiDAR archives to a temp directory. + 3. Inventory LiDAR tiles — enumerate .tif / .img files, check CRS + and native resolution of each survey. + 4. Merge tiles within each LiDAR survey into a GDAL VRT mosaic. + 5. Warp both LiDAR surveys to WGS84 (EPSG:4326) at + TERRAIN_PROCESSED_CELL_DEG resolution. Crop to bounding box. + 6. Three-way elevation merge — priority order, highest to lowest: + LiDAR 2022 (Nooksack survey) — highest resolution, newest vintage + LiDAR 2016 (western survey) — fills gaps in 2022 coverage + USGS DEM (1 arc-second) — floor; covers full extent of all + radar scopes including distant + terrain beyond LiDAR coverage + (Cascades, far ridges for ATC shadow) + Any cell with no data from any source → elevation 0.0 m (water). 7. Material classification: Load S-57 ENC (US5WA45M.000) via GDAL/OGR. Apply classification rules described in TERRAIN section above. @@ -1500,7 +1542,8 @@ PIPELINE (runs in order) shadow_boat_NNN.u8 uint8 visibility masks for boat waypoints; NNN = zero-padded waypoint index terrain_meta.json grid dimensions, lat/lon origin, cell size, - source file checksums, processing date, + checksums for all three source files, + processing date, boat mask waypoint lat/lon list RUNTIME VALIDATION @@ -1522,8 +1565,8 @@ OUTPUT FILES (map/lidar_processed/) waypoint lat/lon list used for nearest-mask lookup These files are the only terrain inputs at runtime. - The raw zip archives in map/lidar_raw/ are never opened by - the exhibit binary. + The raw source files in map/lidar_raw/ and map/charts_enc/ are + never opened by the exhibit binary. ==================================================================