|
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. |
6 | 30 | """ |
7 | 31 |
|
8 | 32 | from __future__ import annotations |
9 | 33 |
|
10 | 34 | import math |
11 | | -from typing import Sequence |
12 | 35 |
|
13 | 36 |
|
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.""" |
16 | 45 |
|
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) |
20 | 53 |
|
21 | 54 |
|
22 | 55 | 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.""" |
24 | 57 |
|
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