"""Umrechnung zwischen gtadb-Weltkoordinaten, Kacheln und Mosaikpixeln. Spiegelt src/world/coords.js. Beide Seiten müssen dieselben Werte liefern. """ import re TILE_PX = 256 WORLD_HALF = 16384 CHUNK_SIZE = 250 SLICE = {"x0": -1000, "x1": 2000, "y0": -500, "y1": 2500} def tile_for_world(x: float, y: float) -> tuple[int, int]: return (int((WORLD_HALF - y) // TILE_PX), int((x + WORLD_HALF) // TILE_PX)) def slice_tiles() -> list[tuple[int, int]]: r0, c0 = tile_for_world(SLICE["x0"], SLICE["y1"]) r1, c1 = tile_for_world(SLICE["x1"] - 1, SLICE["y0"] + 1) return [(r, c) for r in range(r0, r1 + 1) for c in range(c0, c1 + 1)] def mosaic_origin_px() -> tuple[int, int]: """Pixelversatz der Ausschnittsecke innerhalb des ungeschnittenen Kachelrasters.""" r0, c0 = tile_for_world(SLICE["x0"], SLICE["y1"]) return (SLICE["x0"] + WORLD_HALF - c0 * TILE_PX, (WORLD_HALF - SLICE["y1"]) - r0 * TILE_PX) 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" # [0-9] statt \d: in Python passt \d auch auf andere Ziffernzeichen wie ١ oder 1, in JavaScript nicht. _CHUNK_NAME = re.compile(r"([A-La-l])([1-9][0-9]?)") def _is_index(k) -> bool: return isinstance(k, int) and not isinstance(k, bool) and 0 <= k < CHUNKS_PER_SIDE 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 (_is_index(i) and _is_index(j)): 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.fullmatch(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 def chunk_for_world(x: float, y: float) -> tuple[int, int]: """Spiegel von chunkForWorld in src/world/coords.js: i nach Osten, j von der Nordkante nach Süden.""" return int((x - SLICE["x0"]) // CHUNK_SIZE), int((SLICE["y1"] - y) // CHUNK_SIZE)