fix(ui): T-1172 — clip river dots/confluences/mouths against the drawn waterline
Jeroen's hands-on report: rivers continuing under the ocean. Tyre's ruling implemented: the skeleton is rung-independent, the drawn coast is rung-indexed (warp cutoff admits more octaves per rung), so reconciliation is a presentation-frame operation — a draw-time clip against the SAME per-cell morphology verdict the terrain painter used, at the rung on screen. New pure module atlas_window_water_clip.gd: cell resolution across both paths (single-window direct; tile mode selects the containing tile by each tile's OWN echoed n with nearest- wrap re-expression against that tile's canonical center — response-is- source-of-truth + wrap discipline reused, not reinvented). Strict drop (no snap); offshore mouths suppressed (return with real termini in T-1170 — retirement markers at the clip sites); basins untouched; fail-open wherever no composite data has arrived (the clip refines presentation, never gates data). The _pos split feeds the SAME wrap- resolved district to both draw position and clip test so they can never disagree about the wrap image. 49 new tests incl. antimeridian and mid-progressive-arrival fail-open; revert-verified with precise attribution (breaking water detection fails exactly the 3 water tests, fail-open/land tests stay green); smoke-suite stub crash under a real driver caught and fixed (headless skip-gating masked it). 7 suites regression-free; gdlint clean. Tickets: T-1172 Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
This commit is contained in:
@@ -18,7 +18,10 @@ const AtlasWindowNatureOverlay := preload("res://ui/implant/apps/atlas/atlas_win
|
||||
## the same duck-typed-viewer precedent test_atlas_window_overlay.gd's
|
||||
## _ViewerStub already establishes for AtlasWindowOverlay. get_view_zoom()
|
||||
## added post-live-eyeball (coordinator finding, 2026-07-23): _draw() now
|
||||
## reads it for the zoom-compensated marker-size fix.
|
||||
## reads it for the zoom-compensated marker-size fix. is_tile_mode()/
|
||||
## get_district_window()/get_tile_set() added for T-1172 (the water clip) —
|
||||
## district_window/tile_set default to null/an empty stub, matching "no
|
||||
## arrived composite data yet" (the fail-open case) unless a test sets them.
|
||||
class _ViewerStub:
|
||||
var held_granularity_v2: String = "Region"
|
||||
var body_radius_km: float = 6371.0
|
||||
@@ -26,6 +29,9 @@ class _ViewerStub:
|
||||
var held_n: int = 64
|
||||
var view_zoom: float = 1.0
|
||||
var overlay_visibility: Dictionary = {"gen_rivers": true, "gen_basins": false, "gen_attractors": false}
|
||||
var tile_mode: bool = false
|
||||
var district_window: Variant = null
|
||||
var tile_set: Variant = null
|
||||
|
||||
func get_held_granularity_v2() -> String:
|
||||
return held_granularity_v2
|
||||
@@ -48,6 +54,25 @@ class _ViewerStub:
|
||||
func is_overlay_visible(overlay_id: String) -> bool:
|
||||
return bool(overlay_visibility.get(overlay_id, false))
|
||||
|
||||
func is_tile_mode() -> bool:
|
||||
return tile_mode
|
||||
|
||||
func get_district_window() -> Variant:
|
||||
return district_window
|
||||
|
||||
func get_tile_set() -> Variant:
|
||||
return tile_set
|
||||
|
||||
|
||||
## Bare tile-set stub — AtlasWindowNatureOverlay's water-clip lookup only
|
||||
## reaches it through get_tiles(), matching AtlasWindowTileSet's own public
|
||||
## surface (an Array of {"center": Vector2i, "window": Variant}).
|
||||
class _TileSetStub:
|
||||
var tiles: Array = []
|
||||
|
||||
func get_tiles() -> Array:
|
||||
return tiles
|
||||
|
||||
|
||||
static func _mock_layer1(river_class: Variant = null) -> Dictionary:
|
||||
var rn: Dictionary = {
|
||||
@@ -253,3 +278,167 @@ func test_attractor_shape_stroke_widths_are_never_raw_literals() -> void:
|
||||
"raw numeric stroke width(s) in _draw_attractor_shape — route through"
|
||||
+ " px_w (PR #195 Tyre I1): %s" % [offenders]
|
||||
).is_empty()
|
||||
|
||||
|
||||
# =============================================================================
|
||||
# T-1172 — the two-waterline clip. _is_drawn_water()/_district() are called
|
||||
# directly (both are pure lookups with NO draw_*() call of their own — the
|
||||
# _draw()-requires-a-live-render-pass constraint the smoke suite exists for
|
||||
# does not apply to them), matching this file's own "call private helpers
|
||||
# directly when they're the load-bearing unit" precedent
|
||||
# (test_draw_with_zero_grid_dims_returns_before_any_draw_call() above already
|
||||
# calls _draw() itself specifically because its early-return is BEFORE any
|
||||
# draw call — same reasoning here, one level down).
|
||||
# =============================================================================
|
||||
|
||||
|
||||
## A 4x4 District window (n=4, grid_side=4) centered on district (0,0),
|
||||
## spanning [-2, 2) on both axes — cell (0,0) is water, everything else land.
|
||||
## Mirrors test_atlas_window_water_clip.gd's own _mock_4x4_window() fixture
|
||||
## shape (kept local here rather than shared — no cross-test-file import
|
||||
## precedent in this cluster).
|
||||
static func _mock_4x4_water_corner_window() -> Dictionary:
|
||||
var morphology := PackedByteArray()
|
||||
morphology.resize(16)
|
||||
for i in range(16):
|
||||
morphology[i] = 8 # AlluvialPlain — land
|
||||
morphology[0] = 0 # OpenOcean — the single water cell, row 0 col 0
|
||||
return {"center": [0, 0], "n": 4, "granularity_v2": "District", "morphology": morphology}
|
||||
|
||||
|
||||
func _ctx_for(viewer_stub: _ViewerStub) -> Dictionary:
|
||||
return {
|
||||
"grid_w": 256.0,
|
||||
"grid_h": 128.0,
|
||||
"radius_km": 0.0, # no-radius: 1 heightmap pixel = 1 district metre (simplest math)
|
||||
"held_center": viewer_stub.held_center,
|
||||
"held_n": viewer_stub.held_n,
|
||||
"cell_px": 16.0,
|
||||
"cols": 0,
|
||||
"granularity_v2": viewer_stub.held_granularity_v2,
|
||||
"view_zoom": viewer_stub.view_zoom,
|
||||
}
|
||||
|
||||
|
||||
## Single-window mode: a district position resolving to a LAND cell must not
|
||||
## be clipped (_is_drawn_water() returns false — the dot draws).
|
||||
func test_is_drawn_water_false_for_a_land_cell_single_window() -> void:
|
||||
var stub := _ViewerStub.new()
|
||||
stub.district_window = _mock_4x4_water_corner_window()
|
||||
var o = _make_overlay(stub)
|
||||
var ctx: Dictionary = _ctx_for(stub)
|
||||
assert_bool(o._is_drawn_water(Vector2(1.5, 1.5), ctx)).override_failure_message(
|
||||
"a district position over a LAND cell must not be clipped"
|
||||
).is_false()
|
||||
|
||||
|
||||
## Single-window mode: a district position resolving to a WATER cell must be
|
||||
## clipped (_is_drawn_water() returns true — the caller skips drawing).
|
||||
func test_is_drawn_water_true_for_a_water_cell_single_window() -> void:
|
||||
var stub := _ViewerStub.new()
|
||||
stub.district_window = _mock_4x4_water_corner_window()
|
||||
var o = _make_overlay(stub)
|
||||
var ctx: Dictionary = _ctx_for(stub)
|
||||
assert_bool(o._is_drawn_water(Vector2(-1.5, -1.5), ctx)).override_failure_message(
|
||||
"a district position over a WATER (OpenOcean) cell must be clipped"
|
||||
).is_true()
|
||||
|
||||
|
||||
## Tile mode: same land/water split, but the composite data arrives via
|
||||
## get_tile_set().get_tiles() instead of get_district_window() — proving the
|
||||
## clip predicate reaches BOTH path shapes, per the coordinator's explicit
|
||||
## "both path shapes exercised" ask.
|
||||
func test_is_drawn_water_works_in_tile_mode_land() -> void:
|
||||
var stub := _ViewerStub.new()
|
||||
stub.tile_mode = true
|
||||
var ts := _TileSetStub.new()
|
||||
ts.tiles = [{"center": Vector2i.ZERO, "window": _mock_4x4_water_corner_window()}]
|
||||
stub.tile_set = ts
|
||||
var o = _make_overlay(stub)
|
||||
var ctx: Dictionary = _ctx_for(stub)
|
||||
assert_bool(o._is_drawn_water(Vector2(1.5, 1.5), ctx)).override_failure_message(
|
||||
"tile mode: a district position over a LAND cell must not be clipped"
|
||||
).is_false()
|
||||
|
||||
|
||||
func test_is_drawn_water_works_in_tile_mode_water() -> void:
|
||||
var stub := _ViewerStub.new()
|
||||
stub.tile_mode = true
|
||||
var ts := _TileSetStub.new()
|
||||
ts.tiles = [{"center": Vector2i.ZERO, "window": _mock_4x4_water_corner_window()}]
|
||||
stub.tile_set = ts
|
||||
var o = _make_overlay(stub)
|
||||
var ctx: Dictionary = _ctx_for(stub)
|
||||
assert_bool(o._is_drawn_water(Vector2(-1.5, -1.5), ctx)).override_failure_message(
|
||||
"tile mode: a district position over a WATER cell must be clipped"
|
||||
).is_true()
|
||||
|
||||
|
||||
## Tyre's rule 5: NO arrived composite data at the queried position (single-
|
||||
## window mode, window is null — the pre-arrival state) must FAIL OPEN — the
|
||||
## clip is a presentation refinement, never a data gate.
|
||||
func test_is_drawn_water_fails_open_with_no_composite_data_single_window() -> void:
|
||||
var stub := _ViewerStub.new()
|
||||
stub.district_window = null # nothing arrived yet
|
||||
var o = _make_overlay(stub)
|
||||
var ctx: Dictionary = _ctx_for(stub)
|
||||
assert_bool(o._is_drawn_water(Vector2(0.0, 0.0), ctx)).override_failure_message(
|
||||
"no arrived composite data must fail OPEN (draw the dot), never clip"
|
||||
).is_false()
|
||||
|
||||
|
||||
## Same fail-open guarantee in tile mode: no tile set at all (get_tile_set()
|
||||
## returns null, matching the viewer's own pre-enter_orbital() state).
|
||||
func test_is_drawn_water_fails_open_with_no_tile_set() -> void:
|
||||
var stub := _ViewerStub.new()
|
||||
stub.tile_mode = true
|
||||
stub.tile_set = null
|
||||
var o = _make_overlay(stub)
|
||||
var ctx: Dictionary = _ctx_for(stub)
|
||||
assert_bool(o._is_drawn_water(Vector2(0.0, 0.0), ctx)).override_failure_message(
|
||||
"no tile set at all must fail OPEN (draw the dot), never clip"
|
||||
).is_false()
|
||||
|
||||
|
||||
## Fail-open ALSO covers "a tile set exists but no tile covers this position
|
||||
## yet" (mid-progressive-arrival) — the coordinator's own "briefly-unclipped
|
||||
## dot during progressive arrival is fine and self-heals" framing.
|
||||
func test_is_drawn_water_fails_open_when_no_tile_covers_the_position() -> void:
|
||||
var stub := _ViewerStub.new()
|
||||
stub.tile_mode = true
|
||||
var ts := _TileSetStub.new()
|
||||
ts.tiles = [{"center": Vector2i(500, 500), "window": null}] # far away, unarrived
|
||||
stub.tile_set = ts
|
||||
var o = _make_overlay(stub)
|
||||
var ctx: Dictionary = _ctx_for(stub)
|
||||
assert_bool(o._is_drawn_water(Vector2(0.0, 0.0), ctx)).is_false()
|
||||
|
||||
|
||||
## Mouths must be SUPPRESSED (not snapped, not dimmed) on drawn water and
|
||||
## render exactly as today on drawn land — this suite covers the SHARED
|
||||
## predicate _draw_rivers() calls for river cells/confluences/mouths alike
|
||||
## (_is_drawn_water() itself has no notion of "which feature type" — that's
|
||||
## by design, per the ruling's "same predicate" wording for rule 3). A
|
||||
## dedicated assertion here pins the WORDING intent (mouth-specific rule 3)
|
||||
## even though the underlying mechanism is identical to the river-cell tests
|
||||
## above — a future refactor that special-cases mouths differently should
|
||||
## still trip this.
|
||||
func test_mouth_position_on_water_is_suppressed_same_predicate_as_rivers() -> void:
|
||||
var stub := _ViewerStub.new()
|
||||
stub.district_window = _mock_4x4_water_corner_window()
|
||||
var o = _make_overlay(stub)
|
||||
var ctx: Dictionary = _ctx_for(stub)
|
||||
assert_bool(o._is_drawn_water(Vector2(-1.9, -1.9), ctx)).override_failure_message(
|
||||
"a mouth position over drawn water must resolve as clipped, via the SAME"
|
||||
+ " predicate river cells/confluences use — no separate snap/dim path"
|
||||
).is_true()
|
||||
|
||||
|
||||
func test_mouth_position_on_land_is_not_suppressed() -> void:
|
||||
var stub := _ViewerStub.new()
|
||||
stub.district_window = _mock_4x4_water_corner_window()
|
||||
var o = _make_overlay(stub)
|
||||
var ctx: Dictionary = _ctx_for(stub)
|
||||
assert_bool(o._is_drawn_water(Vector2(1.9, 1.9), ctx)).override_failure_message(
|
||||
"a mouth position over drawn land must render exactly as today (not clipped)"
|
||||
).is_false()
|
||||
|
||||
@@ -67,7 +67,13 @@ static func _dummy_renderer_active() -> bool:
|
||||
## called with — the whole point of this smoke suite (post-live-eyeball,
|
||||
## coordinator finding 2026-07-23) is proving markers stay visible at the
|
||||
## REAL orbital fit zoom, not an artificially large test zoom that would
|
||||
## mask the zoom-compensation bug the fix addresses.
|
||||
## mask the zoom-compensation bug the fix addresses. is_tile_mode()/
|
||||
## get_district_window()/get_tile_set() added for T-1172 (the water clip) —
|
||||
## defaults to single-window mode with NO arrived composite (district_window
|
||||
## null), the fail-open case, so these smoke tests keep drawing every marker
|
||||
## exactly as before the clip existed (this file's own job is proving the
|
||||
## draw calls paint pixels at all, not exercising the clip's water-detection
|
||||
## branch — that's test_atlas_window_nature_overlay.gd's job).
|
||||
class _ViewerStub:
|
||||
var held_granularity_v2: String = "Region"
|
||||
var body_radius_km: float = 6371.0
|
||||
@@ -75,6 +81,9 @@ class _ViewerStub:
|
||||
var held_n: int = 64
|
||||
var view_zoom: float = 1.0
|
||||
var overlay_visibility: Dictionary = {"gen_rivers": true, "gen_basins": true, "gen_attractors": true}
|
||||
var tile_mode: bool = false
|
||||
var district_window: Variant = null
|
||||
var tile_set: Variant = null
|
||||
|
||||
func get_held_granularity_v2() -> String:
|
||||
return held_granularity_v2
|
||||
@@ -97,6 +106,15 @@ class _ViewerStub:
|
||||
func is_overlay_visible(overlay_id: String) -> bool:
|
||||
return bool(overlay_visibility.get(overlay_id, false))
|
||||
|
||||
func is_tile_mode() -> bool:
|
||||
return tile_mode
|
||||
|
||||
func get_district_window() -> Variant:
|
||||
return district_window
|
||||
|
||||
func get_tile_set() -> Variant:
|
||||
return tile_set
|
||||
|
||||
|
||||
## A dense scatter of river cells spanning the whole held window's canvas
|
||||
## footprint (not clustered in one corner) — a genuine "does the composite
|
||||
|
||||
@@ -0,0 +1,236 @@
|
||||
## T-1172: pure-function tests for AtlasWindowWaterClip — the two-waterline
|
||||
## clip's cell-lookup math (cell_grid_side_for_window/morphology_zone_in_window/
|
||||
## resolve_morphology_zone). Split into its own file matching this cluster's
|
||||
## own "one pure-geometry file, one test file" precedent
|
||||
## (test_atlas_window_geometry_nature.gd next to atlas_window_geometry.gd's
|
||||
## nature-overlay additions).
|
||||
class_name TestAtlasWindowWaterClip
|
||||
extends GdUnitTestSuite
|
||||
|
||||
const AtlasWindowWaterClip := preload("res://ui/implant/apps/atlas/atlas_window_water_clip.gd")
|
||||
|
||||
const MORPHOLOGY_OPEN_OCEAN: int = 0
|
||||
const MORPHOLOGY_LAND: int = 8 # AlluvialPlain — any non-water zone works
|
||||
|
||||
|
||||
## A window dict shaped exactly like a real DistrictWindowLayer — `center`
|
||||
## as a [x,y] array (the msgpack-decoded wire shape, matching every other
|
||||
## mock window in this cluster's tests), `n` districts wide, `granularity_v2`
|
||||
## District (1:1 cell:district, the simplest case), and a `grid_side x
|
||||
## grid_side` morphology array where `grid_side == n`.
|
||||
static func _mock_district_window(
|
||||
center: Vector2i, n: int, morphology: PackedByteArray
|
||||
) -> Dictionary:
|
||||
return {
|
||||
"center": [center.x, center.y],
|
||||
"n": n,
|
||||
"granularity_v2": "District",
|
||||
"morphology": morphology,
|
||||
}
|
||||
|
||||
|
||||
# =============================================================================
|
||||
# cell_grid_side_for_window — mirrors AtlasWindowOverlay.cell_grid_side_for_window()
|
||||
# =============================================================================
|
||||
|
||||
|
||||
func test_cell_grid_side_district_is_n_unchanged() -> void:
|
||||
var w := {"n": 32, "granularity_v2": "District"}
|
||||
assert_int(AtlasWindowWaterClip.cell_grid_side_for_window(w)).is_equal(32)
|
||||
|
||||
|
||||
func test_cell_grid_side_quarter_is_n_times_four() -> void:
|
||||
var w := {"n": 16, "granularity_v2": "Quarter"}
|
||||
assert_int(AtlasWindowWaterClip.cell_grid_side_for_window(w)).is_equal(64)
|
||||
|
||||
|
||||
func test_cell_grid_side_region_is_n_over_hundred_rounded() -> void:
|
||||
var w := {"n": 6400, "granularity_v2": "Region"}
|
||||
assert_int(AtlasWindowWaterClip.cell_grid_side_for_window(w)).is_equal(64)
|
||||
|
||||
|
||||
func test_cell_grid_side_region_floors_at_one() -> void:
|
||||
var w := {"n": 1, "granularity_v2": "Region"}
|
||||
assert_int(AtlasWindowWaterClip.cell_grid_side_for_window(w)).is_equal(1)
|
||||
|
||||
|
||||
func test_cell_grid_side_unknown_granularity_falls_back_to_district() -> void:
|
||||
var w := {"n": 32} # no granularity_v2 key at all
|
||||
assert_int(AtlasWindowWaterClip.cell_grid_side_for_window(w)).is_equal(32)
|
||||
|
||||
|
||||
# =============================================================================
|
||||
# morphology_zone_in_window — single-window cell lookup
|
||||
# =============================================================================
|
||||
|
||||
|
||||
## A 4x4 District window (n=4, grid_side=4) centered on district (0,0),
|
||||
## spanning [-2, 2) on both axes. Cell (0,0) [top-left, covering district
|
||||
## x in [-2,-1), y in [-2,-1)] is water; the rest is land.
|
||||
static func _mock_4x4_window() -> Dictionary:
|
||||
var morphology := PackedByteArray()
|
||||
morphology.resize(16)
|
||||
for i in range(16):
|
||||
morphology[i] = MORPHOLOGY_LAND
|
||||
morphology[0] = MORPHOLOGY_OPEN_OCEAN # row 0, col 0
|
||||
return _mock_district_window(Vector2i.ZERO, 4, morphology)
|
||||
|
||||
|
||||
func test_morphology_zone_in_window_reads_the_water_cell() -> void:
|
||||
var w: Dictionary = _mock_4x4_window()
|
||||
# District (-1.5, -1.5) falls in cell (row 0, col 0) — the water cell.
|
||||
var zone: int = AtlasWindowWaterClip.morphology_zone_in_window(Vector2(-1.5, -1.5), w)
|
||||
assert_int(zone).is_equal(MORPHOLOGY_OPEN_OCEAN)
|
||||
|
||||
|
||||
func test_morphology_zone_in_window_reads_a_land_cell() -> void:
|
||||
var w: Dictionary = _mock_4x4_window()
|
||||
# District (1.5, 1.5) falls in cell (row 3, col 3) — land.
|
||||
var zone: int = AtlasWindowWaterClip.morphology_zone_in_window(Vector2(1.5, 1.5), w)
|
||||
assert_int(zone).is_equal(MORPHOLOGY_LAND)
|
||||
|
||||
|
||||
func test_morphology_zone_in_window_outside_extent_is_no_data() -> void:
|
||||
var w: Dictionary = _mock_4x4_window()
|
||||
var zone: int = AtlasWindowWaterClip.morphology_zone_in_window(Vector2(100.0, 100.0), w)
|
||||
assert_int(zone).is_equal(AtlasWindowWaterClip.MORPHOLOGY_ZONE_NO_DATA)
|
||||
|
||||
|
||||
func test_morphology_zone_in_window_null_window_is_no_data() -> void:
|
||||
var zone: int = AtlasWindowWaterClip.morphology_zone_in_window(Vector2.ZERO, null)
|
||||
assert_int(zone).is_equal(AtlasWindowWaterClip.MORPHOLOGY_ZONE_NO_DATA)
|
||||
|
||||
|
||||
func test_morphology_zone_in_window_missing_morphology_array_is_no_data() -> void:
|
||||
var w := {"center": [0, 0], "n": 4, "granularity_v2": "District"}
|
||||
var zone: int = AtlasWindowWaterClip.morphology_zone_in_window(Vector2.ZERO, w)
|
||||
assert_int(zone).is_equal(AtlasWindowWaterClip.MORPHOLOGY_ZONE_NO_DATA)
|
||||
|
||||
|
||||
func test_morphology_zone_in_window_zero_n_is_no_data() -> void:
|
||||
var w := {
|
||||
"center": [0, 0], "n": 0, "granularity_v2": "District", "morphology": PackedByteArray()
|
||||
}
|
||||
var zone: int = AtlasWindowWaterClip.morphology_zone_in_window(Vector2.ZERO, w)
|
||||
assert_int(zone).is_equal(AtlasWindowWaterClip.MORPHOLOGY_ZONE_NO_DATA)
|
||||
|
||||
|
||||
## The exact top-left/bottom-right boundary districts must resolve to the
|
||||
## edge cells, not silently miss due to an off-by-one in the containment
|
||||
## test — [-2, 2) is half-open, so -2.0 is IN, 2.0 is OUT.
|
||||
func test_morphology_zone_in_window_boundary_inclusive_at_min() -> void:
|
||||
var w: Dictionary = _mock_4x4_window()
|
||||
var zone: int = AtlasWindowWaterClip.morphology_zone_in_window(Vector2(-2.0, -2.0), w)
|
||||
assert_int(zone).is_equal(MORPHOLOGY_OPEN_OCEAN)
|
||||
|
||||
|
||||
func test_morphology_zone_in_window_boundary_exclusive_at_max() -> void:
|
||||
var w: Dictionary = _mock_4x4_window()
|
||||
var zone: int = AtlasWindowWaterClip.morphology_zone_in_window(Vector2(2.0, 2.0), w)
|
||||
assert_int(zone).is_equal(AtlasWindowWaterClip.MORPHOLOGY_ZONE_NO_DATA)
|
||||
|
||||
|
||||
# =============================================================================
|
||||
# resolve_morphology_zone — the single-window / tile-mode dispatch
|
||||
# =============================================================================
|
||||
|
||||
|
||||
func test_resolve_single_window_mode_reads_the_window_directly() -> void:
|
||||
var w: Dictionary = _mock_4x4_window()
|
||||
var zone: int = AtlasWindowWaterClip.resolve_morphology_zone(
|
||||
Vector2(-1.5, -1.5), false, w, [], 0
|
||||
)
|
||||
assert_int(zone).is_equal(MORPHOLOGY_OPEN_OCEAN)
|
||||
|
||||
|
||||
func test_resolve_single_window_mode_null_window_is_no_data() -> void:
|
||||
var zone: int = AtlasWindowWaterClip.resolve_morphology_zone(Vector2.ZERO, false, null, [], 0)
|
||||
assert_int(zone).is_equal(AtlasWindowWaterClip.MORPHOLOGY_ZONE_NO_DATA)
|
||||
|
||||
|
||||
## Tile mode: two tiles, each its own 4x4 window, centered far enough apart
|
||||
## that a queried district only falls inside ONE of them.
|
||||
func test_resolve_tile_mode_finds_the_containing_tile() -> void:
|
||||
var morph_a := PackedByteArray()
|
||||
morph_a.resize(16)
|
||||
for i in range(16):
|
||||
morph_a[i] = MORPHOLOGY_LAND
|
||||
var tile_a := {
|
||||
"center": Vector2i(0, 0), "window": _mock_district_window(Vector2i.ZERO, 4, morph_a)
|
||||
}
|
||||
|
||||
var morph_b := PackedByteArray()
|
||||
morph_b.resize(16)
|
||||
for i in range(16):
|
||||
morph_b[i] = MORPHOLOGY_OPEN_OCEAN
|
||||
var tile_b := {
|
||||
"center": Vector2i(100, 0), "window": _mock_district_window(Vector2i(100, 0), 4, morph_b)
|
||||
}
|
||||
|
||||
var tiles: Array = [tile_a, tile_b]
|
||||
var zone_in_a: int = AtlasWindowWaterClip.resolve_morphology_zone(
|
||||
Vector2(0.0, 0.0), true, null, tiles, 0
|
||||
)
|
||||
var zone_in_b: int = AtlasWindowWaterClip.resolve_morphology_zone(
|
||||
Vector2(100.0, 0.0), true, null, tiles, 0
|
||||
)
|
||||
assert_int(zone_in_a).override_failure_message(
|
||||
"a district position inside tile A's extent must read tile A's own cell"
|
||||
).is_equal(MORPHOLOGY_LAND)
|
||||
assert_int(zone_in_b).override_failure_message(
|
||||
"a district position inside tile B's extent must read tile B's own cell"
|
||||
).is_equal(MORPHOLOGY_OPEN_OCEAN)
|
||||
|
||||
|
||||
func test_resolve_tile_mode_position_outside_every_tile_is_no_data() -> void:
|
||||
var morph := PackedByteArray()
|
||||
morph.resize(16)
|
||||
var tile := {"center": Vector2i(0, 0), "window": _mock_district_window(Vector2i.ZERO, 4, morph)}
|
||||
var zone: int = AtlasWindowWaterClip.resolve_morphology_zone(
|
||||
Vector2(9999.0, 9999.0), true, null, [tile], 0
|
||||
)
|
||||
assert_int(zone).is_equal(AtlasWindowWaterClip.MORPHOLOGY_ZONE_NO_DATA)
|
||||
|
||||
|
||||
## A tile whose window hasn't arrived yet (`window: null`, matching
|
||||
## AtlasWindowTileSet.get_tiles()'s own "unarrived" shape) must be skipped,
|
||||
## not crash — the scan continues to the next tile / falls through to
|
||||
## MORPHOLOGY_ZONE_NO_DATA.
|
||||
func test_resolve_tile_mode_skips_unarrived_tiles() -> void:
|
||||
var unarrived := {"center": Vector2i(0, 0), "window": null}
|
||||
var zone: int = AtlasWindowWaterClip.resolve_morphology_zone(
|
||||
Vector2(0.0, 0.0), true, null, [unarrived], 0
|
||||
)
|
||||
assert_int(zone).is_equal(AtlasWindowWaterClip.MORPHOLOGY_ZONE_NO_DATA)
|
||||
|
||||
|
||||
func test_resolve_tile_mode_empty_tile_list_is_no_data() -> void:
|
||||
var zone: int = AtlasWindowWaterClip.resolve_morphology_zone(Vector2.ZERO, true, null, [], 0)
|
||||
assert_int(zone).is_equal(AtlasWindowWaterClip.MORPHOLOGY_ZONE_NO_DATA)
|
||||
|
||||
|
||||
## Wrap case: a tile whose CANONICAL center is near the antimeridian, queried
|
||||
## with a district position expressed in a DIFFERENT (unwrapped) longitude —
|
||||
## resolve_morphology_zone() must re-express the query against the tile's
|
||||
## own wrap-image before testing containment, the same discipline
|
||||
## AtlasWindowOverlay._draw_tile_mosaic() already uses for drawing.
|
||||
func test_resolve_tile_mode_wraps_the_query_to_the_tiles_own_image() -> void:
|
||||
var cols := 100
|
||||
var morph := PackedByteArray()
|
||||
morph.resize(16)
|
||||
for i in range(16):
|
||||
morph[i] = MORPHOLOGY_OPEN_OCEAN
|
||||
# Tile's canonical center is column 2 (near the origin side of the wrap).
|
||||
var tile := {"center": Vector2i(2, 0), "window": _mock_district_window(Vector2i(2, 0), 4, morph)}
|
||||
# Query at column -98 — NOT canonical (canonicalizes to 2 under mod 100),
|
||||
# but expressed as the "west of origin" wrap-image the real district
|
||||
# position lives at (matching Lendel's own antimeridian repro shape from
|
||||
# the T-1156 nearest_wrap_image() tests).
|
||||
var zone: int = AtlasWindowWaterClip.resolve_morphology_zone(
|
||||
Vector2(-98.0, 0.0), true, null, [tile], cols
|
||||
)
|
||||
assert_int(zone).override_failure_message(
|
||||
"a query expressed in a different (non-canonical) wrap-image of the same"
|
||||
+ " real position must still resolve against the tile whose canonical"
|
||||
+ " center it's periodic-equivalent to"
|
||||
).is_equal(MORPHOLOGY_OPEN_OCEAN)
|
||||
Reference in New Issue
Block a user