"""Gesamtansicht des Ausschnitts aus den fertigen Chunk-Dateien. Zeichnet ausschließlich das, was wirklich ausgeliefert wird — kein Kartenbild darunter. Damit fallen Fehler auf, die kein Unit-Test sieht: gespiegelte Achsen, versetzte Chunks, Beschriftungen der Originalkarte, die als Geometrie durchgerutscht sind. cd tools/extract && uv run python overview.py """ import json from pathlib import Path from PIL import Image, ImageDraw from leonida.coords import SLICE OUT = Path("../../public/data/vice-a") DST = Path("debug/overview.png") SCALE = 0.5 # Pixel je Meter WATER = (36, 72, 104) LAND = (150, 162, 120) SURFACE = {"sand": (226, 210, 150), "park": (120, 160, 90), "urban": (176, 176, 172)} ROAD = (74, 74, 78) BRIDGE = (196, 92, 92) PALM = (40, 190, 70) TALL = 120.0 # Meter, ab der ein Gebäude die hellste Färbung bekommt def _to_px(ring, ox, oy): """Chunk-lokale three.js-Koordinaten (x, z) -> Bildpixel.""" return [((x + ox - SLICE["x0"]) * SCALE, (SLICE["y1"] - (oy - z)) * SCALE) for x, z in ring] def _draw(draw, rings, ox, oy, fill, outline=None): """Außenring füllen, Löcher wieder mit Wasserfarbe ausstanzen.""" draw.polygon(_to_px(rings[0], ox, oy), fill=fill, outline=outline) for hole in rings[1:]: draw.polygon(_to_px(hole, ox, oy), fill=WATER) def render(out_dir: Path, dst: Path) -> dict: size = int((SLICE["x1"] - SLICE["x0"]) * SCALE) img = Image.new("RGB", (size, size), WATER) draw = ImageDraw.Draw(img) chunks = [json.loads(f.read_text()) for f in sorted(out_dir.glob("chunk_*.json"))] stats = {"land": 0, "strassen": 0, "bruecken": 0, "gebaeude": 0, "palmen": 0} # Ebene für Ebene über alle Chunks, damit nichts von einem Nachbarchunk überdeckt wird. for chunk in chunks: ox, oy = chunk["origin"][0], -chunk["origin"][1] for rings in chunk["land"]: _draw(draw, rings, ox, oy, LAND) stats["land"] += 1 for chunk in chunks: ox, oy = chunk["origin"][0], -chunk["origin"][1] for surface in chunk["surfaces"]: _draw(draw, surface["poly"], ox, oy, SURFACE[surface["kind"]]) for chunk in chunks: ox, oy = chunk["origin"][0], -chunk["origin"][1] for road in chunk["roads"]: _draw(draw, road["poly"], ox, oy, BRIDGE if road["bridge"] else ROAD) stats["bruecken" if road["bridge"] else "strassen"] += 1 for chunk in chunks: ox, oy = chunk["origin"][0], -chunk["origin"][1] for building in chunk["buildings"]: t = min(1.0, building["height"] / TALL) shade = (int(70 + 170 * t), int(70 + 120 * t), int(80 + 60 * t)) _draw(draw, building["poly"], ox, oy, shade, outline=(30, 30, 30)) stats["gebaeude"] += 1 for x, z in chunk["palms"]: px, py = _to_px([(x, z)], ox, oy)[0] draw.ellipse([px - 1.6, py - 1.6, px + 1.6, py + 1.6], fill=PALM) stats["palmen"] += 1 dst.parent.mkdir(parents=True, exist_ok=True) img.save(dst) return stats if __name__ == "__main__": print(render(OUT, DST), "->", DST)