feat(coords): Chunk-Namen als Planquadrat A1 bis L12
Co-Authored-By: Claude Haiku 4.5 <noreply@anthropic.com>
This commit is contained in:
1 parent
44108f94f4
commit
2f63779363
5 files changed
+120
-2
No files matched your search
@@ -2,6 +2,8 @@
|
||||
|
||||
Spiegelt src/world/coords.js. Beide Seiten müssen dieselben Werte liefern.
|
||||
"""
|
||||
import re
|
||||
|
||||
TILE_PX = 256
|
||||
WORLD_HALF = 16384
|
||||
CHUNK_SIZE = 250
|
||||
@@ -26,3 +28,23 @@ def mosaic_origin_px() -> tuple[int, int]:
|
||||
|
||||
def pixel_to_world(px: int, py: int) -> tuple[float, float]:
|
||||
return (SLICE["x0"] + px, SLICE["y1"] - py)
|
||||
|
||||
|
||||
CHUNKS_PER_SIDE = (SLICE["x1"] - SLICE["x0"]) // CHUNK_SIZE # 12
|
||||
CHUNK_COLUMNS = "ABCDEFGHIJKL"
|
||||
_CHUNK_NAME = re.compile(r"^([A-La-l])([1-9]\d?)$")
|
||||
|
||||
|
||||
def chunk_name(i: int, j: int) -> str | None:
|
||||
"""Planquadrat-Name wie src/world/coords.js: Spalte A–L aus i, Zeile 1–12 aus j. A1 = Nordwest."""
|
||||
if not (0 <= i < CHUNKS_PER_SIDE and 0 <= j < CHUNKS_PER_SIDE):
|
||||
return None
|
||||
return f"{CHUNK_COLUMNS[i]}{j + 1}"
|
||||
|
||||
|
||||
def parse_chunk_name(name: str) -> tuple[int, int] | None:
|
||||
"""Umkehrung von chunk_name. Akzeptiert Kleinschreibung, None außerhalb A1–L12."""
|
||||
match = _CHUNK_NAME.match(str(name))
|
||||
if not match or int(match.group(2)) > CHUNKS_PER_SIDE:
|
||||
return None
|
||||
return CHUNK_COLUMNS.index(match.group(1).upper()), int(match.group(2)) - 1
|
||||
@@ -1,4 +1,10 @@
|
||||
from leonida.coords import SLICE, pixel_to_world, slice_tiles, tile_for_world
|
||||
import json
|
||||
from pathlib import Path
|
||||
|
||||
from leonida.coords import SLICE, chunk_name, parse_chunk_name, pixel_to_world, slice_tiles, tile_for_world
|
||||
|
||||
# Derselbe Beispielsatz wie tests/coords.test.js — JavaScript und Python dürfen nicht auseinanderlaufen.
|
||||
NAMES = json.loads((Path(__file__).resolve().parents[3] / "tests/fixtures/chunk-names.json").read_text())
|
||||
|
||||
def test_tile_of_vice_beach():
|
||||
assert tile_for_world(1409.4, 2803.2) == (53, 69)
|
||||
@@ -13,3 +19,27 @@ def test_pixel_origin_is_slice_corner():
|
||||
# Pixel (0,0) des beschnittenen Mosaiks ist die Nordwest-Ecke des Ausschnitts.
|
||||
assert pixel_to_world(0, 0) == (SLICE["x0"], SLICE["y1"])
|
||||
assert pixel_to_world(2999, 2999) == (SLICE["x0"] + 2999, SLICE["y1"] - 2999)
|
||||
|
||||
|
||||
def test_chunk_names_match_the_shared_examples():
|
||||
for name, i, j in NAMES["pairs"]:
|
||||
assert chunk_name(i, j) == name
|
||||
assert parse_chunk_name(name) == (i, j)
|
||||
|
||||
|
||||
def test_chunk_names_accept_lowercase():
|
||||
for name, i, j in NAMES["lowercase"]:
|
||||
assert parse_chunk_name(name) == (i, j)
|
||||
|
||||
|
||||
def test_chunk_names_reject_everything_outside_a1_to_l12():
|
||||
for name in NAMES["invalid"]:
|
||||
assert parse_chunk_name(name) is None
|
||||
assert chunk_name(12, 0) is None
|
||||
assert chunk_name(0, -1) is None
|
||||
|
||||
|
||||
def test_chunk_names_round_trip_for_all_144_chunks():
|
||||
for i in range(12):
|
||||
for j in range(12):
|
||||
assert parse_chunk_name(chunk_name(i, j)) == (i, j)
|
||||
Reference in new issue
Block a user