Files
settled-reach/client/ui/implant/apps/atlas/atlas_window_water_clip.gd
T
jpmschweitzerandClaude Fable 5 c31cc6220e feat(ui): T-1170 B3 — course polyline drawing at District/Quarter; clip restructured per Ruling 3g
_draw() splits into two independent gates: the Layer-1-gated skeleton
path (Region chords, clip retained) and the NEW DistrictWindowLayer-
gated course path — build_course_render_plan() (pure, render-free-
testable) consumed by draw_polyline with _zs-compensated widths and
opacities from the Araminta revisit tables; mouth double-rings at
Mouth termini only (EdgeDrain/ContinuesBeyondWindow/None: three
meanings, one presentation — draw to last point, stop, documented);
zero water clip on the course path by construction (courses carry
rung-consistent termini). CourseTerminus wire vocabulary kept re-
pointable pending A2's real serde names; synthetic Ruling-3h fixtures
mean the suites need zero changes when the server payload lands. Real
gap found and fixed: window arrival never redrew the nature overlay
after the first fit (one line in _on_window_ready — courses would
miss every window swap post-pan). Water-clip header rewritten to
RESTRUCTURED status (retired on course rungs; permanent at Region
until Region goes windowed, T-1143 ruling 2). Revert-verified
(visibility-gate bypass -> 4 named failures). geometry-nature
112/112, nature-overlay 58/58, viewer 78/78, zero collateral; full
sweep 3928/3928 after the full-import bootstrap; gdlint clean (viewer
1016->1017, pre-existing overage rides T-1158).

Tickets: T-1170

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
2026-07-23 13:05:40 +02:00

172 lines
9.2 KiB
GDScript

extends RefCounted
## T-1172 — the river-skeleton waterline-clip fix. Pure geometry, split into
## its own file (not folded into atlas_window_geometry.gd, which is already
## close to the gdlint max-file-lines cap): the river skeleton's own SOURCE
## (server/src/atlas/drainage.rs) is filtered against the RAW heightmap sea
## level, but the DRAWN ocean this client actually paints is the derived
## MorphologyZone verdict (server/src/atlas/district_profile.rs) — which
## post-T-1162 includes the coast-warp invention (the drawn coastline is
## deterministically displaced from the heightmap coast) and, at Region
## rung, aggregates to 204.8 km cells. These are two independently-computed
## waterlines that can legitimately disagree; Tyre's ruling (T-1172): no
## single server waterline is well-defined, so the fix is a CLIENT draw-time
## clip against whichever composite cell is currently ON SCREEN at a given
## river dot's position — strict drop, no snap (a dot that lands on drawn
## water is simply not drawn; Region's 205 km cells may amputate a river's
## final coastal dots, an accepted cost per the ruling).
##
## T-1170 Ruling 3g update (RESTRUCTURED, not blanket-retired): the clip is
## RETIRED for the District/Quarter COURSE-drawing rungs
## (AtlasWindowNatureOverlay._draw_course_path()/_draw_one_course()) —
## courses carry real rung-consistent termini invented server-side against
## the SAME rung's drawn coast, so the clip's job is already done there. This
## file's clip machinery is STILL LIVE and used at the Region SKELETON path
## (_draw_skeleton_chords()/_segment_touches_drawn_water()) — Region still
## draws the whole-body skeleton against a rung-dependent drawn coast, which
## is precisely the presentation-frame reconciliation this file exists for.
## The Region clip is PERMANENT-UNTIL-REGION-GOES-WINDOWED (T-1143 ruling 2's
## progressive tiling) — when Region itself becomes a windowed rung, it
## inherits windowed courses too, and this file retires entirely at that
## point, not before.
##
## const AtlasWindowWaterClip := preload("res://ui/implant/apps/atlas/atlas_window_water_clip.gd")
const AtlasWindowGeometryRef := preload("res://ui/implant/apps/atlas/atlas_window_geometry.gd")
## Sentinel returned by the lookups below when no arrived composite data
## covers the queried position — either the position is outside every
## held/tiled window's own extent, or the window/tile at that position
## hasn't arrived yet. The caller (AtlasWindowNatureOverlay) must FAIL OPEN
## on this sentinel (draw the dot) — Tyre's rule 5: the clip is a
## presentation refinement, never a data gate. Chosen as -1 (not a legal
## MorphologyZone discriminant, which is always >= 0) so it can never be
## mistaken for a real "not water" zone.
const MORPHOLOGY_ZONE_NO_DATA: int = -1
## The derived per-cell grid side length (CELLS) for a window dict `w` — a
## DELIBERATE duplicate of AtlasWindowOverlay.cell_grid_side_for_window(),
## not a shared call, matching this codebase's own "each file owns its own
## reading of a small pure lookup rather than force a dependency" precedent
## (atlas_overlay_colors.gd's header doc states this explicitly for the
## color-palette case; the SAME rationale applies here: atlas_window_overlay.gd
## already depends on atlas_window_geometry.gd, so a dependency back from
## there — or from this file, if it lived there — would risk a circular or
## at least confusing import graph). Mirrors
## server/src/atlas/layer_proxy.rs's `WindowGranularity::cell_grid_side`
## exactly, matching the canonical function's own doc byte-for-byte in intent.
static func cell_grid_side_for_window(w: Dictionary) -> int:
var n: int = int(w.get("n", 0))
var granularity_v2 := str(w.get("granularity_v2", "District"))
match granularity_v2:
"Quarter":
return n * 4
"Region":
return maxi(roundi(float(n) / 100.0), 1)
_:
return n
## Resolve a FRACTIONAL district position to the MorphologyZone discriminant
## of the composite cell covering it, for a SINGLE window dict `w` (the
## single-window rung path: District/Quarter, and each individual Region
## tile in tile mode share this same per-window shape). Returns
## MORPHOLOGY_ZONE_NO_DATA if `w` is null/malformed, has no morphology array,
## or `district` falls outside `w`'s own `[center - n/2, center + n/2)`
## extent (the SAME containment convention
## AtlasWindowGeometry.district_to_canvas_local() uses, so a position judged
## "inside" here is exactly the position that would draw as part of THIS
## window's composite on screen — no separate containment rule to drift out
## of sync with the actual paint).
static func morphology_zone_in_window(district: Vector2, w: Variant) -> int:
if not w is Dictionary:
return MORPHOLOGY_ZONE_NO_DATA
var window: Dictionary = w
var center_raw: Variant = window.get("center", [0, 0])
var center: Vector2i = (
Vector2i(int(center_raw[0]), int(center_raw[1])) if center_raw is Array else Vector2i.ZERO
)
var n: int = int(window.get("n", 0))
if n <= 0:
return MORPHOLOGY_ZONE_NO_DATA
var half: float = float(n) * 0.5
var local_x: float = district.x - (float(center.x) - half)
var local_y: float = district.y - (float(center.y) - half)
if local_x < 0.0 or local_x >= float(n) or local_y < 0.0 or local_y >= float(n):
return MORPHOLOGY_ZONE_NO_DATA
var morphology: Variant = window.get("morphology")
if not (morphology is PackedByteArray or morphology is Array):
return MORPHOLOGY_ZONE_NO_DATA
var grid_side: int = cell_grid_side_for_window(window)
if grid_side <= 0:
return MORPHOLOGY_ZONE_NO_DATA
# T-1172 round 2: SHARED index formula with the terrain painter
# (AtlasWindowGeometry.cell_index_for_local_offset() — see its own doc
# for why this is now factored out instead of duplicated).
var cell: Vector2i = AtlasWindowGeometryRef.cell_index_for_local_offset(
local_x, local_y, n, grid_side
)
var idx: int = cell.y * grid_side + cell.x
if idx < 0 or idx >= morphology.size():
return MORPHOLOGY_ZONE_NO_DATA
return int(morphology[idx])
## Resolve a fractional district position to a MorphologyZone discriminant
## across BOTH viewer modes — the single dispatch point
## AtlasWindowNatureOverlay's clip predicate calls, so it never needs its own
## is_tile_mode() branch. Single-window mode: one direct
## morphology_zone_in_window() call against `single_window`. Tile mode:
## linear scan of `tiles` (Array of {"center": Vector2i, "window": Variant},
## AtlasWindowTileSet.get_tiles()'s own shape) for whichever tile's ON-SCREEN
## extent contains the position — each tile's OWN echoed `window["n"]` is
## used for the actual containment test (not TILE_N assumed), matching this
## cluster's "the response is the source of truth for what it actually
## contains" precedent, since a clamped/still-arriving tile's real extent
## can differ from the nominal per-tile request size.
##
## **Live round 2 fix (coordinator's trace, T-1172):** the wrap resolution
## MUST mirror AtlasWindowOverlay._draw_tile_mosaic()'s own
## `draw_col = nearest_wrap_image(center.x, held_center.x, cols)` EXACTLY —
## wrap the TILE'S OWN CENTER toward `held_center` (the viewer's currently-
## displayed reference frame), then test the (already held-center-wrapped)
## query `district` against that RESOLVED center. The original version did
## the inverse — wrapped the QUERY toward the tile's raw CANONICAL center —
## which is not the same operation and silently tested containment against
## the WRONG wrap-image of the tile for any tile whose canonical center is
## far from `held_center` (i.e. any tile that needs wrapping to appear
## on-screen at all — confirmed live: a dot at district.x=-9569 visibly
## sitting on the painter's WEST wrap-image of the seam tile
## (canonical center 12739, drawn at draw_col=-6400) was tested by the old
## code against that tile's EAST/canonical span `[9539, 15939)` instead —
## landed inside it by coincidence (mod arithmetic), read a real but
## WRONG-LOCATION land cell, and never clipped). `district.x` is assumed
## ALREADY wrap-resolved near `held_center` by the caller (AtlasWindowNatureOverlay.
## _district()'s own contract) — this function does not re-wrap it, only the
## tile centers, exactly mirroring the painter's own asymmetry (the painter
## never wrap-resolves the query either — canvas-local coordinates are
## already in the held-center frame by construction).
static func resolve_morphology_zone(
district: Vector2, is_tile_mode: bool, single_window: Variant, tiles: Array, cols: int,
held_center_x: int = 0
) -> int:
if not is_tile_mode:
return morphology_zone_in_window(district, single_window)
for tile: Dictionary in tiles:
var window: Variant = tile.get("window")
if not window is Dictionary:
continue
var tile_center: Vector2i = tile.get("center", Vector2i.ZERO)
var draw_col: int = tile_center.x
if cols > 0:
draw_col = AtlasWindowGeometryRef.nearest_wrap_image(tile_center.x, held_center_x, cols)
var effective_window: Dictionary = window
if draw_col != tile_center.x:
effective_window = (window as Dictionary).duplicate()
effective_window["center"] = [draw_col, tile_center.y]
var zone: int = morphology_zone_in_window(district, effective_window)
if zone != MORPHOLOGY_ZONE_NO_DATA:
return zone
return MORPHOLOGY_ZONE_NO_DATA