Skip to content

Commit 90bbb2e

Browse files
fix(ahbg): stop reconstructing UCNS centers in presentation geometry
1 parent cadb4fa commit 90bbb2e

1 file changed

Lines changed: 46 additions & 31 deletions

File tree

ahbg/presentation/geometry.py

Lines changed: 46 additions & 31 deletions
Original file line numberDiff line numberDiff line change
@@ -1,43 +1,58 @@
1-
"""Seed of Life presentation geometry.
2-
3-
The tile is the centerpoint. Each circle has radius equal to the distance
4-
between adjacent centers. This module renders geometry; it does not define game
5-
movement or adjacency authority.
1+
# === MODULE_BUILD ===
2+
# id: ahbg_presentation_display_transform
3+
# module_name: geometry
4+
# module_kind: adapter
5+
# summary: scales already-supplied UCNS source coordinates into SVG display coordinates without reconstructing or selecting geometry
6+
# owner: AHBG presentation
7+
# public_surface: source_to_display, center_distance
8+
# internal_surface: none
9+
# auth_boundary: none
10+
# storage_boundary: none
11+
# network_boundary: none
12+
# user_data_boundary: none
13+
# admin_only: false
14+
# tests: ahbg/presentation/tests/test_presentation.py
15+
# rollout: used only by presentation tests and equivalent browser transform
16+
# rollback: inline display scaling or remove presentation package; no mechanics effect
17+
# requires: caller-supplied UCNS-derived x/y source coordinates
18+
# since: 2026-08-31
19+
# unresolved: none
20+
# === END MODULE_BUILD ===
21+
22+
"""Presentation-only transform of source-backed center coordinates.
23+
24+
This module does not derive Seed-of-Life centers, adjacency, orientation, or
25+
nesting. It only scales coordinates already supplied by the declared UCNS source
26+
into display pixels; optional y inversion is the SVG screen-coordinate transform.
27+
28+
Usage guidance:
29+
``source_to_display(x, y, scale=64.0)`` after validating the snapshot.
630
"""
731

832
from __future__ import annotations
933

1034
import math
11-
from typing import Sequence
1235

1336

14-
def axial_to_xy(q: int, r: int, radius: float) -> tuple[float, float]:
15-
"""Map already-supplied axial coordinates into presentation pixels."""
37+
def source_to_display(
38+
x: float,
39+
y: float,
40+
scale: float,
41+
*,
42+
invert_y: bool = True,
43+
) -> tuple[float, float]:
44+
"""Scale source coordinates for display without changing their topology."""
1645

17-
if radius <= 0:
18-
raise ValueError("radius must be positive")
19-
return (radius * (q + r / 2), radius * (math.sqrt(3) / 2) * r)
46+
if isinstance(x, bool) or not isinstance(x, (int, float)):
47+
raise ValueError("x must be numeric and nonboolean")
48+
if isinstance(y, bool) or not isinstance(y, (int, float)):
49+
raise ValueError("y must be numeric and nonboolean")
50+
if isinstance(scale, bool) or not isinstance(scale, (int, float)) or scale <= 0:
51+
raise ValueError("scale must be positive numeric and nonboolean")
52+
return float(x) * float(scale), (-float(y) if invert_y else float(y)) * float(scale)
2053

2154

2255
def center_distance(left: tuple[float, float], right: tuple[float, float]) -> float:
23-
return math.hypot(left[0] - right[0], left[1] - right[1])
56+
"""Measure distance between already-supplied source/display points."""
2457

25-
26-
def visual_one_radius_pairs(
27-
tiles: Sequence[tuple[int, int]], radius: float
28-
) -> tuple[tuple[tuple[int, int], tuple[int, int]], ...]:
29-
"""Return center pairs one display radius apart; presentation use only."""
30-
31-
points = {item: axial_to_xy(item[0], item[1], radius) for item in tiles}
32-
pairs = []
33-
items = list(tiles)
34-
for index, left in enumerate(items):
35-
for right in items[index + 1 :]:
36-
if math.isclose(
37-
center_distance(points[left], points[right]),
38-
radius,
39-
rel_tol=1e-9,
40-
abs_tol=1e-9,
41-
):
42-
pairs.append((left, right))
43-
return tuple(pairs)
58+
return math.hypot(left[0] - right[0], left[1] - right[1])

0 commit comments

Comments
 (0)