The atlas 'regional' screen now opens the LADDER at the canonical orbital frame (Region granularity, whole body fitted and centered) and wheel zoom descends continuously — cursor-anchored, unclamped across rungs, with progressive refinement (held composite keeps drawing, finer rung swaps in place on arrival; no blank frame, no mode flip). Full-zoom-out resets to the canonical planetary frame per Jeroen's HARD condition (is_fully_zoomed_out = extent >= body circumference, not a zoom-value heuristic). The district_screen nav hop is deleted — D-013 restored: descent is a zoom gesture, not a nav push. AtlasViewer's heightmap-texture path is unreachable from nav (code intact; overlay surface deferred, see report/tickets). Rung selection: design doc §5's literal formula has NO legal District band at any real viewport (visual-tolerance band and n=64 coverage ceiling never overlap — pinned by executable boundary tests at 1600x900); select_rung() splits it into a coverage ceiling (decides Region) then the 2x visual tolerance (District vs Quarter), documented at the function. In practice the ladder steps Region -> Quarter directly. Wire: window_granularity_v2 encoded (omitted at District for byte-compat), granularity_v2 echoed value keyed + staleness-guarded end to end; Region clamp mirror replicates the server's bounded halving loop (no closed form). MIN/MAX_ZOOM widened to [0.0005, 64] — the old 0.5 floor would have clamped a real body's canonical fit zoom, violating the reset condition. Real pre-existing bug fixed in atlas_window_overlay.gd: the draw path used echoed n as both cell-grid dimension and district extent — only coincidentally correct at District granularity; Quarter/Region would have read wrong array offsets. cell_grid_side_for_window() now mirrors the server's WindowGranularity::cell_grid_side. Tests: +26 pure-function geometry tests, new 30-test zoom-ladder suite, extensions across the window cache/request/overlay/delivery suites. Full suite 3518 green; cold-parse clean.
601 lines
28 KiB
GDScript
601 lines
28 KiB
GDScript
## T-1142 (Jeroen's second/third hands-on findings): pure-function tests for
|
|
## AtlasWindowViewer's fit-and-center math (fit_window_view) and pole-wall
|
|
## pan clamp (clamp_pan_offset_to_pole_wall) — both extracted specifically so
|
|
## the "viewport + n -> zoom/offset" transform is unit-testable without a
|
|
## live Control tree.
|
|
class_name TestAtlasWindowGeometry
|
|
extends GdUnitTestSuite
|
|
|
|
const AtlasWindowGeometry := preload("res://ui/implant/apps/atlas/atlas_window_geometry.gd")
|
|
const AtlasDescendGeometry := preload("res://ui/implant/apps/atlas/atlas_descend_geometry.gd")
|
|
|
|
const MIN_ZOOM: float = 0.5
|
|
const MAX_ZOOM: float = 8.0
|
|
const CELL_PIXEL_SIZE: float = 16.0
|
|
|
|
|
|
# =============================================================================
|
|
# fit_window_view — the "postage stamp" fix (item 2)
|
|
# =============================================================================
|
|
|
|
|
|
## n=32, cell_px=16 -> native composite is 512x512. T-1145 item 1: COVER
|
|
## fit derives zoom from the LARGER viewport dimension (1920, not 1080) with
|
|
## NO margin factor — zoom = 1920 / 512 = 3.75 — well inside [MIN_ZOOM,
|
|
## MAX_ZOOM], so the clamp is a no-op here.
|
|
func test_fit_window_view_computes_expected_zoom_for_a_wide_viewport() -> void:
|
|
var fit: Dictionary = AtlasWindowGeometry.fit_window_view(
|
|
Vector2(1920.0, 1080.0), 32, CELL_PIXEL_SIZE, MIN_ZOOM, MAX_ZOOM
|
|
)
|
|
var expected_zoom: float = 1920.0 / 512.0
|
|
assert_float(fit["zoom"]).is_equal_approx(expected_zoom, 0.001)
|
|
|
|
|
|
## The composite must be CENTERED — offset.x/.y each leave an equal margin on
|
|
## both sides of the (n*cell_px*zoom)-sized composite (a NEGATIVE "margin" is
|
|
## fine and expected under cover — it just means the composite overhangs
|
|
## that axis, checked separately by test_fit_window_view_covers_with_no_gap).
|
|
func test_fit_window_view_centers_the_composite() -> void:
|
|
var viewport := Vector2(1920.0, 1080.0)
|
|
var fit: Dictionary = AtlasWindowGeometry.fit_window_view(
|
|
viewport, 32, CELL_PIXEL_SIZE, MIN_ZOOM, MAX_ZOOM
|
|
)
|
|
var composite_scaled: float = 32.0 * CELL_PIXEL_SIZE * float(fit["zoom"])
|
|
var offset: Vector2 = fit["offset"]
|
|
# The composite's right/bottom edge is offset + composite_scaled — the
|
|
# margin on the far side must equal the margin on the near side (offset).
|
|
var right_margin: float = viewport.x - (offset.x + composite_scaled)
|
|
var bottom_margin: float = viewport.y - (offset.y + composite_scaled)
|
|
assert_float(right_margin).is_equal_approx(offset.x, 0.01)
|
|
assert_float(bottom_margin).is_equal_approx(offset.y, 0.01)
|
|
|
|
|
|
## T-1145 item 1 (Jeroen's round-2 finding, KALLAST window): a wide viewport
|
|
## must show NO side margins — the composite's LONG axis (the one the cover
|
|
## zoom is derived from) must land EXACTLY at the viewport edges (offset ~=
|
|
## 0 on that axis), and the SHORT axis must OVERHANG past both edges
|
|
## (negative margin — the composite is bigger than the viewport there,
|
|
## exactly what "cover" means). This is the literal assertion the coordinator
|
|
## asked for: no side margins at 16:9.
|
|
func test_fit_window_view_covers_with_no_gap_on_the_long_axis() -> void:
|
|
var viewport := Vector2(1920.0, 1080.0)
|
|
var fit: Dictionary = AtlasWindowGeometry.fit_window_view(
|
|
viewport, 32, CELL_PIXEL_SIZE, MIN_ZOOM, MAX_ZOOM
|
|
)
|
|
var composite_scaled: float = 32.0 * CELL_PIXEL_SIZE * float(fit["zoom"])
|
|
var offset: Vector2 = fit["offset"]
|
|
# Long axis (X, 1920 > 1080): the composite must span EXACTLY the
|
|
# viewport width — zero margin on both sides.
|
|
assert_float(offset.x).override_failure_message(
|
|
"the long (cover) axis must have NO side margin — offset.x should be ~0"
|
|
).is_equal_approx(0.0, 0.5)
|
|
var right_margin: float = viewport.x - (offset.x + composite_scaled)
|
|
assert_float(right_margin).override_failure_message(
|
|
"the long (cover) axis's far edge must have NO margin either"
|
|
).is_equal_approx(0.0, 0.5)
|
|
# Short axis (Y, 1080 < 1920): the composite must OVERHANG (negative
|
|
# margin) past BOTH edges — this is the data that extends into pan-space.
|
|
assert_float(offset.y).override_failure_message(
|
|
"the short axis must OVERHANG past the top edge (negative offset)"
|
|
).is_less(0.0)
|
|
|
|
|
|
## A TALL viewport (portrait) must cover the same way, just with the axes
|
|
## swapped — long axis (Y) gets zero margin, short axis (X) overhangs.
|
|
func test_fit_window_view_covers_a_tall_viewport_too() -> void:
|
|
var viewport := Vector2(1080.0, 1920.0)
|
|
var fit: Dictionary = AtlasWindowGeometry.fit_window_view(
|
|
viewport, 32, CELL_PIXEL_SIZE, MIN_ZOOM, MAX_ZOOM
|
|
)
|
|
var offset: Vector2 = fit["offset"]
|
|
assert_float(offset.y).override_failure_message(
|
|
"the long (cover) axis (Y, portrait) must have NO side margin"
|
|
).is_equal_approx(0.0, 0.5)
|
|
assert_float(offset.x).override_failure_message(
|
|
"the short axis (X, portrait) must overhang past the left edge"
|
|
).is_less(0.0)
|
|
|
|
|
|
## A perfectly square viewport needs NO overhang on either axis — cover and
|
|
## contain agree exactly at a 1:1 aspect ratio (the degenerate case where
|
|
## "long" and "short" axis are the same).
|
|
func test_fit_window_view_square_viewport_has_no_overhang_either_axis() -> void:
|
|
var fit: Dictionary = AtlasWindowGeometry.fit_window_view(
|
|
Vector2(1024.0, 1024.0), 32, CELL_PIXEL_SIZE, MIN_ZOOM, MAX_ZOOM
|
|
)
|
|
assert_vector(fit["offset"]).is_equal_approx(Vector2.ZERO, Vector2(0.5, 0.5))
|
|
|
|
|
|
## Jeroen's exact bug: an n=32 composite (512px native) in a real ~1920px
|
|
## viewport must NOT render at zoom=1.0 (the old, unfitted "postage stamp"
|
|
## behavior) — the fit must scale it up to fill (now: COVER) the viewport.
|
|
func test_fit_window_view_scales_up_a_small_composite_to_fill_the_viewport() -> void:
|
|
var fit: Dictionary = AtlasWindowGeometry.fit_window_view(
|
|
Vector2(1920.0, 1080.0), 32, CELL_PIXEL_SIZE, MIN_ZOOM, MAX_ZOOM
|
|
)
|
|
assert_float(fit["zoom"]).override_failure_message(
|
|
"a 512px composite in a 1920x1080 viewport must be scaled UP, not left at 1.0"
|
|
).is_greater(1.0)
|
|
|
|
|
|
## A huge n (e.g. n=64 at a tiny viewport) must clamp to MIN_ZOOM, never
|
|
## shrink the composite into illegibility below the floor.
|
|
func test_fit_window_view_clamps_to_min_zoom_for_a_tiny_viewport() -> void:
|
|
var fit: Dictionary = AtlasWindowGeometry.fit_window_view(
|
|
Vector2(200.0, 150.0), 64, CELL_PIXEL_SIZE, MIN_ZOOM, MAX_ZOOM
|
|
)
|
|
assert_float(fit["zoom"]).is_equal_approx(MIN_ZOOM, 0.001)
|
|
|
|
|
|
## A small n (e.g. n=2) at a huge viewport must clamp to MAX_ZOOM, never
|
|
## scale past the ceiling.
|
|
func test_fit_window_view_clamps_to_max_zoom_for_a_tiny_composite() -> void:
|
|
var fit: Dictionary = AtlasWindowGeometry.fit_window_view(
|
|
Vector2(3840.0, 2160.0), 2, CELL_PIXEL_SIZE, MIN_ZOOM, MAX_ZOOM
|
|
)
|
|
assert_float(fit["zoom"]).is_equal_approx(MAX_ZOOM, 0.001)
|
|
|
|
|
|
## Degenerate inputs (zero viewport, zero n) must not divide by zero — a safe
|
|
## fallback (zoom=1.0, offset=ZERO), never a crash or NaN.
|
|
func test_fit_window_view_degenerate_inputs_are_safe() -> void:
|
|
var fit_zero_viewport: Dictionary = AtlasWindowGeometry.fit_window_view(
|
|
Vector2.ZERO, 32, CELL_PIXEL_SIZE, MIN_ZOOM, MAX_ZOOM
|
|
)
|
|
assert_float(fit_zero_viewport["zoom"]).is_equal_approx(1.0, 0.001)
|
|
var fit_zero_n: Dictionary = AtlasWindowGeometry.fit_window_view(
|
|
Vector2(1920.0, 1080.0), 0, CELL_PIXEL_SIZE, MIN_ZOOM, MAX_ZOOM
|
|
)
|
|
assert_float(fit_zero_n["zoom"]).is_equal_approx(1.0, 0.001)
|
|
|
|
|
|
# =============================================================================
|
|
# clamp_pan_offset_to_pole_wall — item 5 (pole hard wall, row axis only)
|
|
# =============================================================================
|
|
|
|
|
|
## Deep inside the valid range (window nowhere near a pole), the clamp must
|
|
## be a no-op — offset passes through unchanged.
|
|
func test_pole_wall_clamp_is_a_noop_far_from_the_poles() -> void:
|
|
var offset := Vector2(10.0, 20.0)
|
|
var clamped: Vector2 = AtlasWindowGeometry.clamp_pan_offset_to_pole_wall(
|
|
offset, Vector2(1920.0, 1080.0), Vector2i(0, 0), 32, 4785, CELL_PIXEL_SIZE, 1.0
|
|
)
|
|
assert_that(clamped).is_equal(offset)
|
|
|
|
|
|
## X is NEVER clamped by the pole wall (item 6: east-west is seamless) — even
|
|
## an absurdly large X offset passes through untouched.
|
|
func test_pole_wall_clamp_never_touches_x() -> void:
|
|
var offset := Vector2(999999.0, 0.0)
|
|
var clamped: Vector2 = AtlasWindowGeometry.clamp_pan_offset_to_pole_wall(
|
|
offset, Vector2(1920.0, 1080.0), Vector2i(0, 0), 32, 4785, CELL_PIXEL_SIZE, 1.0
|
|
)
|
|
assert_float(clamped.x).is_equal_approx(999999.0, 0.001)
|
|
|
|
|
|
## The core pole-wall behavior: dragging FAR past the north pole (offset.y
|
|
## driven to an extreme) must clamp — the resulting offset must be LESS than
|
|
## the extreme requested, and a SECOND, even-more-extreme drag must produce
|
|
## the SAME clamped value (further dragging is inert once pinned at the wall).
|
|
func test_pole_wall_clamp_pins_offset_when_dragged_past_the_pole() -> void:
|
|
var rows_half := 100
|
|
var held_center := Vector2i(0, 90) # near the south pole already (row 90 of 100)
|
|
var extreme_offset := Vector2(0.0, 5000.0) # a huge downward drag
|
|
var clamped: Vector2 = AtlasWindowGeometry.clamp_pan_offset_to_pole_wall(
|
|
extreme_offset, Vector2(800.0, 800.0), held_center, 32, rows_half, CELL_PIXEL_SIZE, 1.0
|
|
)
|
|
assert_float(clamped.y).override_failure_message(
|
|
"an extreme drag toward the pole must be clamped, not pass through"
|
|
).is_less(extreme_offset.y)
|
|
|
|
var even_more_extreme := Vector2(0.0, 50000.0)
|
|
var clamped_again: Vector2 = AtlasWindowGeometry.clamp_pan_offset_to_pole_wall(
|
|
even_more_extreme, Vector2(800.0, 800.0), held_center, 32, rows_half, CELL_PIXEL_SIZE, 1.0
|
|
)
|
|
assert_float(clamped_again.y).override_failure_message(
|
|
"further dragging past an already-pinned wall must be inert (same clamped value)"
|
|
).is_equal_approx(clamped.y, 0.01)
|
|
|
|
|
|
## Symmetric check on the north side: a huge UPWARD drag near the north pole
|
|
## also clamps.
|
|
func test_pole_wall_clamp_pins_offset_on_the_north_side_too() -> void:
|
|
var rows_half := 100
|
|
var held_center := Vector2i(0, -90) # near the north pole
|
|
var extreme_offset := Vector2(0.0, -5000.0) # a huge upward drag
|
|
var clamped: Vector2 = AtlasWindowGeometry.clamp_pan_offset_to_pole_wall(
|
|
extreme_offset, Vector2(800.0, 800.0), held_center, 32, rows_half, CELL_PIXEL_SIZE, 1.0
|
|
)
|
|
assert_float(clamped.y).override_failure_message(
|
|
"an extreme drag toward the north pole must be clamped"
|
|
).is_greater(extreme_offset.y)
|
|
|
|
|
|
## rows_half <= 0 (a no-radius body, or a degenerate district_extent()) means
|
|
## "no wall concept" — the clamp is a no-op, matching
|
|
## canonicalize_district_center()'s own no-radius identity disposition.
|
|
func test_pole_wall_clamp_is_noop_when_rows_half_is_zero() -> void:
|
|
var offset := Vector2(0.0, 999999.0)
|
|
var clamped: Vector2 = AtlasWindowGeometry.clamp_pan_offset_to_pole_wall(
|
|
offset, Vector2(800.0, 800.0), Vector2i(0, 0), 32, 0, CELL_PIXEL_SIZE, 1.0
|
|
)
|
|
assert_that(clamped).is_equal(offset)
|
|
|
|
|
|
## Tiny-body edge case (documented open item in atlas_window_viewer.gd's own
|
|
## _clamp_offset_to_pole_wall doc): a window TALLER than the whole planet's
|
|
## row span (n=64 window, rows_half=10 -> pole-to-pole is only 20 districts)
|
|
## must not crash or produce an inverted/degenerate clamp range — the offset
|
|
## still comes back as a finite Vector2, and repeated extreme drags still
|
|
## converge to a stable pinned value (not NaN, not unbounded).
|
|
func test_pole_wall_clamp_handles_a_window_taller_than_the_planet() -> void:
|
|
var rows_half := 10
|
|
var held_n := 64
|
|
var held_center := Vector2i(0, 0)
|
|
var clamped: Vector2 = AtlasWindowGeometry.clamp_pan_offset_to_pole_wall(
|
|
Vector2(0.0, 999999.0), Vector2(800.0, 800.0), held_center, held_n, rows_half,
|
|
CELL_PIXEL_SIZE, 1.0
|
|
)
|
|
assert_bool(is_finite(clamped.y)).override_failure_message(
|
|
"a window taller than the planet's row span must still produce a finite clamp"
|
|
).is_true()
|
|
var clamped_again: Vector2 = AtlasWindowGeometry.clamp_pan_offset_to_pole_wall(
|
|
Vector2(0.0, 9999999.0), Vector2(800.0, 800.0), held_center, held_n, rows_half,
|
|
CELL_PIXEL_SIZE, 1.0
|
|
)
|
|
assert_float(clamped_again.y).is_equal_approx(clamped.y, 0.01)
|
|
|
|
|
|
# =============================================================================
|
|
# Cross-check: clamp bounds derived from district_extent() (the SAME source
|
|
# canonicalize_district_center() uses) — confirms the two T-1142 fixes (item
|
|
# 5 pole wall, item 6a wrap/clamp) agree on what "the pole" even is.
|
|
# =============================================================================
|
|
|
|
|
|
func test_pole_wall_rows_half_matches_canonicalize_rows_half() -> void:
|
|
var radius_km := 6238.4 # GJ380c
|
|
var extent: Dictionary = AtlasDescendGeometry.district_extent(radius_km)
|
|
var rows_half: int = int(extent["rows_half"])
|
|
# A center exactly at (0, rows_half) must canonicalize to itself (already
|
|
# at the pole boundary, not past it) — pins that the SAME rows_half both
|
|
# fixes consume describes an inclusive boundary, not an exclusive one.
|
|
var canonical: Vector2i = AtlasDescendGeometry.canonicalize_district_center(
|
|
Vector2i(0, rows_half), radius_km
|
|
)
|
|
assert_int(canonical.y).is_equal(rows_half)
|
|
|
|
|
|
# =============================================================================
|
|
# T-1153: select_rung() — the §5 rung-selection rule, split into TWO tests
|
|
# per select_rung()'s own doc: a COVERAGE ceiling decides Region (can a
|
|
# District window even span this much world), and the `2x` visual-tolerance
|
|
# rule (design doc §5: "select the coarsest rung whose cell spacing <=
|
|
# 2*(E/C)") decides District vs. Quarter for whatever's under that ceiling.
|
|
# =============================================================================
|
|
|
|
|
|
## A tight sample spacing (deep zoom-in — small E over a large C) must select
|
|
## Quarter (512 m), the finest legal rung — 2*(E/C) is far below District's
|
|
## 2,048 m spacing at this ratio.
|
|
func test_select_rung_picks_quarter_at_a_tight_sample_spacing() -> void:
|
|
# E=2000m over C=1000px -> sample spacing 2 m/px -> threshold 4 m. Even
|
|
# Quarter (512 m) is coarser than the threshold, so select_rung() falls
|
|
# through to the FINEST legal rung (its own documented fallback) rather
|
|
# than returning something even finer that doesn't exist — Quarter.
|
|
var rung: String = AtlasWindowGeometry.select_rung(2000.0, 1000.0)
|
|
assert_str(rung).is_equal("Quarter")
|
|
|
|
|
|
## A sample spacing that satisfies BOTH District's own `2x` band AND the
|
|
## coverage ceiling selects District — the coarsest rung whose spacing still
|
|
## satisfies the fine-end rule, without exceeding what a District window can
|
|
## physically cover.
|
|
func test_select_rung_picks_district_at_a_moderate_sample_spacing() -> void:
|
|
# E=120,000m (under the 64*2048=131,072m coverage ceiling) over C=100px ->
|
|
# threshold = 2*120000/100 = 2,400m — satisfies District's 2,048m spacing.
|
|
var rung: String = AtlasWindowGeometry.select_rung(120_000.0, 100.0)
|
|
assert_str(rung).is_equal("District")
|
|
|
|
|
|
## An extent past the COVERAGE ceiling (more world than a District window can
|
|
## physically span, regardless of how generous the visual tolerance would
|
|
## otherwise be) must select Region — the coverage test, not the `2x` visual
|
|
## one, is what decides this (select_rung()'s own doc: "the coverage ceiling
|
|
## wins whenever the two disagree").
|
|
func test_select_rung_picks_region_past_the_coverage_ceiling() -> void:
|
|
# E = full Earth-like circumference (~40,075 km) — far past the
|
|
# 64*2048=131,072m District coverage ceiling regardless of canvas_px.
|
|
var rung: String = AtlasWindowGeometry.select_rung(40_075_264.0, 1920.0)
|
|
assert_str(rung).is_equal("Region")
|
|
|
|
|
|
## Exactly AT the coverage ceiling (E == 64*2048 = 131,072m) must still
|
|
## select District if the `2x` band also agrees — the ceiling is `>`, not
|
|
## `>=`, so the boundary value itself stays under District's own test.
|
|
func test_select_rung_coverage_ceiling_boundary_stays_district() -> void:
|
|
var rung: String = AtlasWindowGeometry.select_rung(131_072.0, 100.0)
|
|
assert_str(rung).is_equal("District")
|
|
|
|
|
|
## One metre past the coverage ceiling must flip to Region — confirms the
|
|
## ceiling actually bites right at its own boundary, not one district-window
|
|
## short of it.
|
|
func test_select_rung_one_past_the_coverage_ceiling_is_region() -> void:
|
|
var rung: String = AtlasWindowGeometry.select_rung(131_073.0, 100.0)
|
|
assert_str(rung).is_equal("Region")
|
|
|
|
|
|
## Exactly AT District's `2x` threshold (spacing_m == 2*(E/C)) must select
|
|
## District, not the next-finer rung — the rule is `<=`, not `<`.
|
|
func test_select_rung_district_threshold_boundary_is_inclusive() -> void:
|
|
# District spacing = 2048 m. Choose E/C such that 2*(E/C) == 2048 exactly:
|
|
# E=1024, C=1.0 -> E/C=1024 -> threshold=2048. E=1024 is also comfortably
|
|
# under the coverage ceiling (131,072), so the `2x` test is what's
|
|
# actually being exercised here.
|
|
var rung: String = AtlasWindowGeometry.select_rung(1024.0, 1.0)
|
|
assert_str(rung).is_equal("District")
|
|
|
|
|
|
## Degenerate canvas_px (<=0, an unlaid-out viewport) must fall back to the
|
|
## FINEST rung, never crash or pick the coarsest by dividing by zero — the
|
|
## documented "under-resolve is the safe failure direction" disposition (and
|
|
## must be checked BEFORE the coverage ceiling could otherwise route a
|
|
## degenerate small extent toward Region by accident).
|
|
func test_select_rung_degenerate_canvas_px_falls_back_to_finest() -> void:
|
|
var rung: String = AtlasWindowGeometry.select_rung(1000.0, 0.0)
|
|
assert_str(rung).is_equal("Quarter")
|
|
|
|
|
|
## spacing_for_rung() is select_rung()'s inverse lookup — pin the three known
|
|
## values against the D-243 constants directly (not against RUNG_TABLE
|
|
## indices, which would just restate the implementation).
|
|
func test_spacing_for_rung_matches_d243_constants() -> void:
|
|
assert_float(AtlasWindowGeometry.spacing_for_rung("Quarter")).is_equal_approx(512.0, 0.001)
|
|
assert_float(AtlasWindowGeometry.spacing_for_rung("District")).is_equal_approx(2048.0, 0.001)
|
|
assert_float(AtlasWindowGeometry.spacing_for_rung("Region")).is_equal_approx(204_800.0, 0.001)
|
|
|
|
|
|
## An unknown tag falls back to District — matching the server's own
|
|
## "unknown -> District" posture at every wire-decode boundary.
|
|
func test_spacing_for_rung_unknown_tag_falls_back_to_district() -> void:
|
|
assert_float(AtlasWindowGeometry.spacing_for_rung("Nonsense")).is_equal_approx(2048.0, 0.001)
|
|
|
|
|
|
## The exact scenario that surfaced the coverage-vs-visual-tolerance
|
|
## distinction (live-testing enter_orbital()'s own fit zoom): a whole
|
|
## Earth-like body's circumference (~40,075 km, matching
|
|
## AtlasDescendGeometry.district_extent()'s own cols*DISTRICT_M for
|
|
## radius=6371km) fitted to a 1920px-wide viewport at CELL_PIXEL_SIZE=16 must
|
|
## select Region — this is the direct regression guard for the bug this
|
|
## implementation found and fixed (an earlier version of select_rung()
|
|
## selected District here, which would have meant the canonical orbital
|
|
## frame requests a District-tier derive spanning an entire planet — the
|
|
## exact R1-catastrophe cost scenario the design doc §4 rejects).
|
|
func test_select_rung_at_orbital_fit_zoom_selects_region() -> void:
|
|
var radius_km := 6371.0
|
|
var extent: Dictionary = AtlasDescendGeometry.district_extent(radius_km)
|
|
var n: int = int(extent["cols"])
|
|
var composite_native: float = float(n) * CELL_PIXEL_SIZE
|
|
var viewport := Vector2(1920.0, 1080.0)
|
|
var fit_zoom: float = maxf(viewport.x, viewport.y) / composite_native
|
|
var world_extent: float = AtlasWindowGeometry.world_extent_m(CELL_PIXEL_SIZE, fit_zoom, viewport)
|
|
var rung: String = AtlasWindowGeometry.select_rung(
|
|
world_extent, maxf(viewport.x, viewport.y)
|
|
)
|
|
assert_str(rung).override_failure_message(
|
|
"the canonical orbital fit-zoom (whole-planet view) must select Region,"
|
|
+ " never a District-tier derive spanning an entire planet"
|
|
).is_equal("Region")
|
|
|
|
|
|
## Pinned capture-resolution boundary numbers (1600x900, the coordinator's
|
|
## requested eyeball-capture viewport) — a live executable regression guard
|
|
## for select_rung()'s own doc's worked example. Region releases District's
|
|
## coverage ceiling at _view_zoom ~= 1.5625; District's own `2x` band edge
|
|
## sits at _view_zoom ~= 0.125 — i.e. BELOW (not above) the coverage-ceiling
|
|
## crossing, confirming the two never overlap at this (or any real) canvas
|
|
## size — see select_rung()'s "Tuning knobs" paragraph for what would need
|
|
## to change (DISTRICT_WINDOW_MAX_N, a server-side wire-budget change) to
|
|
## open a real District band.
|
|
func test_select_rung_1600x900_region_district_boundary_zoom() -> void:
|
|
var viewport := Vector2(1600.0, 900.0)
|
|
var canvas_px: float = maxf(viewport.x, viewport.y)
|
|
var boundary_zoom := 1.5625
|
|
var just_inside: float = AtlasWindowGeometry.world_extent_m(
|
|
CELL_PIXEL_SIZE, boundary_zoom * 1.001, viewport
|
|
)
|
|
var just_outside: float = AtlasWindowGeometry.world_extent_m(
|
|
CELL_PIXEL_SIZE, boundary_zoom * 0.999, viewport
|
|
)
|
|
assert_str(AtlasWindowGeometry.select_rung(just_inside, canvas_px)).override_failure_message(
|
|
"zoomed IN past ~1.5625 at 1600x900 must have released the Region coverage ceiling"
|
|
).is_not_equal("Region")
|
|
assert_str(AtlasWindowGeometry.select_rung(just_outside, canvas_px)).override_failure_message(
|
|
"zoomed OUT past ~1.5625 at 1600x900 must still be under the Region coverage ceiling"
|
|
).is_equal("Region")
|
|
|
|
|
|
func test_select_rung_1600x900_district_quarter_boundary_zoom_confirms_no_overlap() -> void:
|
|
var viewport := Vector2(1600.0, 900.0)
|
|
var canvas_px: float = maxf(viewport.x, viewport.y)
|
|
var boundary_zoom := 0.125
|
|
var just_inside: float = AtlasWindowGeometry.world_extent_m(
|
|
CELL_PIXEL_SIZE, boundary_zoom * 1.001, viewport
|
|
)
|
|
var just_outside: float = AtlasWindowGeometry.world_extent_m(
|
|
CELL_PIXEL_SIZE, boundary_zoom * 0.999, viewport
|
|
)
|
|
# Both sides of the District/Quarter `2x`-band boundary read "Region" at
|
|
# 1600x900, NOT "District" — confirming the coverage ceiling (which
|
|
# releases at zoom~=1.5625, far above this boundary) has already forced
|
|
# Region long before the `2x` band's own edge is reached. This is the
|
|
# literal "no overlap" finding, pinned as an executable assertion.
|
|
assert_str(AtlasWindowGeometry.select_rung(just_inside, canvas_px)).is_equal("Region")
|
|
assert_str(AtlasWindowGeometry.select_rung(just_outside, canvas_px)).is_equal("Region")
|
|
|
|
|
|
# =============================================================================
|
|
# T-1153: world_extent_m() — the `E` half of the §5 rule, computed from the
|
|
# viewer's own zoom/viewport state.
|
|
# =============================================================================
|
|
|
|
|
|
## At zoom=1.0, CELL_PIXEL_SIZE=16: one DISTRICT (2,048 m, the fixed display
|
|
## unit — see world_extent_m()'s own doc for why this is rung-INDEPENDENT)
|
|
## occupies 16 screen px, so a 1920px-wide viewport shows
|
|
## 1920/16 * 2048 = 245,760 m.
|
|
func test_world_extent_m_at_zoom_one() -> void:
|
|
var extent: float = AtlasWindowGeometry.world_extent_m(
|
|
CELL_PIXEL_SIZE, 1.0, Vector2(1920.0, 1080.0)
|
|
)
|
|
assert_float(extent).is_equal_approx(1920.0 / CELL_PIXEL_SIZE * 2048.0, 1.0)
|
|
|
|
|
|
## Doubling the zoom must HALVE the displayed world extent — zooming in
|
|
## shows less world, not more.
|
|
func test_world_extent_m_halves_when_zoom_doubles() -> void:
|
|
var extent_1x: float = AtlasWindowGeometry.world_extent_m(
|
|
CELL_PIXEL_SIZE, 1.0, Vector2(1920.0, 1080.0)
|
|
)
|
|
var extent_2x: float = AtlasWindowGeometry.world_extent_m(
|
|
CELL_PIXEL_SIZE, 2.0, Vector2(1920.0, 1080.0)
|
|
)
|
|
assert_float(extent_2x).is_equal_approx(extent_1x * 0.5, 1.0)
|
|
|
|
|
|
## The composite's on-screen footprint is rung-invariant (world_extent_m()'s
|
|
## own doc) — a change in held rung with NO change in zoom/viewport must
|
|
## leave the displayed world extent UNCHANGED. This is the direct regression
|
|
## test for the bug this function's signature once had (a granularity_v2
|
|
## parameter that silently changed the formula per rung, when only zoom
|
|
## should) — the function no longer TAKES a rung parameter at all, so this
|
|
## pins that omission is intentional, not an oversight.
|
|
func test_world_extent_m_has_no_rung_parameter() -> void:
|
|
var extent_a: float = AtlasWindowGeometry.world_extent_m(
|
|
CELL_PIXEL_SIZE, 1.0, Vector2(1920.0, 1080.0)
|
|
)
|
|
var extent_b: float = AtlasWindowGeometry.world_extent_m(
|
|
CELL_PIXEL_SIZE, 1.0, Vector2(1920.0, 1080.0)
|
|
)
|
|
assert_float(extent_a).is_equal_approx(extent_b, 0.001)
|
|
|
|
|
|
## Degenerate zoom (<=0) must not divide by zero — a safe zero extent.
|
|
func test_world_extent_m_degenerate_zoom_is_safe() -> void:
|
|
var extent: float = AtlasWindowGeometry.world_extent_m(
|
|
CELL_PIXEL_SIZE, 0.0, Vector2(1920.0, 1080.0)
|
|
)
|
|
assert_float(extent).is_equal_approx(0.0, 0.001)
|
|
|
|
|
|
# =============================================================================
|
|
# T-1153: is_fully_zoomed_out() — Jeroen's HARD condition's trigger predicate.
|
|
# =============================================================================
|
|
|
|
|
|
func test_is_fully_zoomed_out_true_when_extent_covers_full_circumference() -> void:
|
|
var radius_km := 6371.0
|
|
var circumference_m: float = TAU * radius_km * 1000.0
|
|
assert_bool(AtlasWindowGeometry.is_fully_zoomed_out(circumference_m, radius_km)).is_true()
|
|
assert_bool(
|
|
AtlasWindowGeometry.is_fully_zoomed_out(circumference_m * 1.5, radius_km)
|
|
).is_true()
|
|
|
|
|
|
func test_is_fully_zoomed_out_false_when_extent_is_less_than_circumference() -> void:
|
|
var radius_km := 6371.0
|
|
var circumference_m: float = TAU * radius_km * 1000.0
|
|
assert_bool(
|
|
AtlasWindowGeometry.is_fully_zoomed_out(circumference_m * 0.5, radius_km)
|
|
).is_false()
|
|
|
|
|
|
## A no-radius body (tiny test body) has no circumference concept — never
|
|
## auto-resets, matching enter_orbital()'s own no-radius fallback disposition.
|
|
func test_is_fully_zoomed_out_false_for_no_radius_body() -> void:
|
|
assert_bool(AtlasWindowGeometry.is_fully_zoomed_out(1e12, 0.0)).is_false()
|
|
|
|
|
|
# =============================================================================
|
|
# T-1153: screen_center_to_district() — the shared screen<->district formula
|
|
# behind both the pan-edge refetch and the rung-reselect refetch.
|
|
# =============================================================================
|
|
|
|
|
|
## At the exact center of a symmetric fit (offset centers the composite,
|
|
## zoom=1.0), the screen center must map back to the held center exactly.
|
|
func test_screen_center_to_district_at_rest_returns_held_center() -> void:
|
|
var held_n := 32
|
|
var held_center := Vector2i(10, 20)
|
|
var composite_native: float = float(held_n) * CELL_PIXEL_SIZE
|
|
var viewport := Vector2(composite_native, composite_native)
|
|
var offset := Vector2.ZERO # composite exactly fills the viewport, top-left at origin
|
|
var result: Vector2i = AtlasWindowGeometry.screen_center_to_district(
|
|
viewport, offset, 1.0, CELL_PIXEL_SIZE, held_center, held_n
|
|
)
|
|
assert_that(result).is_equal(held_center)
|
|
|
|
|
|
## Panning the offset must shift the recovered district position in the
|
|
## OPPOSITE direction of the offset shift (dragging the composite right
|
|
## reveals districts to the WEST at screen-center).
|
|
func test_screen_center_to_district_shifts_with_pan_offset() -> void:
|
|
var held_n := 32
|
|
var held_center := Vector2i(0, 0)
|
|
var composite_native: float = float(held_n) * CELL_PIXEL_SIZE
|
|
var viewport := Vector2(composite_native, composite_native)
|
|
var at_rest: Vector2i = AtlasWindowGeometry.screen_center_to_district(
|
|
viewport, Vector2.ZERO, 1.0, CELL_PIXEL_SIZE, held_center, held_n
|
|
)
|
|
var panned: Vector2i = AtlasWindowGeometry.screen_center_to_district(
|
|
viewport, Vector2(CELL_PIXEL_SIZE * 4.0, 0.0), 1.0, CELL_PIXEL_SIZE, held_center, held_n
|
|
)
|
|
assert_int(panned.x).override_failure_message(
|
|
"dragging the composite EAST (positive offset) must reveal districts to the WEST"
|
|
).is_less(at_rest.x)
|
|
|
|
|
|
# =============================================================================
|
|
# T-1153 (moved from atlas_window_viewer.gd for testability): WASD held-pan
|
|
# direction is exercised live only (reads the global Input singleton) —
|
|
# edge-scroll suppression/direction are pure and covered here directly.
|
|
# =============================================================================
|
|
|
|
|
|
func test_is_cursor_edge_scrolling_true_near_an_edge() -> void:
|
|
var result: bool = AtlasWindowGeometry.is_cursor_edge_scrolling(
|
|
true, false, Vector2(800.0, 600.0), Vector2(10.0, 300.0), 24.0
|
|
)
|
|
assert_bool(result).is_true()
|
|
|
|
|
|
func test_is_cursor_edge_scrolling_false_away_from_any_edge() -> void:
|
|
var result: bool = AtlasWindowGeometry.is_cursor_edge_scrolling(
|
|
true, false, Vector2(800.0, 600.0), Vector2(400.0, 300.0), 24.0
|
|
)
|
|
assert_bool(result).is_false()
|
|
|
|
|
|
func test_is_cursor_edge_scrolling_suppressed_when_over_ui() -> void:
|
|
var result: bool = AtlasWindowGeometry.is_cursor_edge_scrolling(
|
|
true, true, Vector2(800.0, 600.0), Vector2(10.0, 300.0), 24.0
|
|
)
|
|
assert_bool(result).is_false()
|
|
|
|
|
|
func test_is_cursor_edge_scrolling_suppressed_without_app_focus() -> void:
|
|
var result: bool = AtlasWindowGeometry.is_cursor_edge_scrolling(
|
|
false, false, Vector2(800.0, 600.0), Vector2(10.0, 300.0), 24.0
|
|
)
|
|
assert_bool(result).is_false()
|
|
|
|
|
|
func test_edge_scroll_direction_points_west_near_left_edge() -> void:
|
|
var direction: Vector2 = AtlasWindowGeometry.edge_scroll_direction(
|
|
Vector2(800.0, 600.0), Vector2(5.0, 300.0), 24.0
|
|
)
|
|
assert_float(direction.x).is_less(0.0)
|
|
assert_float(direction.y).is_equal_approx(0.0, 0.001)
|